¿Cómo hacer múltiples LEFT JOINs con O usar completamente un índice compuesto? (parte 2)

Es para un sistema que calcula cómo los usuarios escanean sus huellas digitales cuando entran / salen del lugar de trabajo. No sé cómo se llama en inglés. Necesito determinar si el usuario llega tarde por la mañana y si el usuario deja el trabajo temprano.

Estatb_scan La tabla contiene la fecha y la hora en que un usuario escanea una huella digital.

CREATE TABLE `tb_scan` (
  `scpercode` varchar(6) DEFAULT NULL,
  `scyear` varchar(4) DEFAULT NULL,
  `scmonth` varchar(2) DEFAULT NULL,
  `scday` varchar(2) DEFAULT NULL,
  `scscantime` datetime,
  KEY `all` (`scyear`,`scmonth`,`scday`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

Tiene más de 100,000 filas, algo como esto

scpercode scyear scmonth scday     scdateandtime
000001    2010      10     10      2016-01-10 08:02:00
000001    2010      10     10      2016-01-02 17:33:00
000001    2010      10     11      2016-01-11 07:48:00
000001    2010      10     11      2016-01-11 17:29:00
000002    2010      10     10      2016-01-10 17:31:00
000002    2010      10     10      2016-01-02 17:28:00
000002    2010      10     11      2016-01-11 05:35:00
000002    2010      10     11      2016-01-11 05:29:00

Y estotb_workday la tabla contiene cada fecha

CREATE TABLE `tb_workday` (
  `wdpercode` varchar(6) DEFAULT NULL,
  `wdshift` varchar(1) DEFAULT NULL,
  `wddate` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1

Tiene filas con una secuencia de fechas como esta:

wdpercode  wdshift wddate
000001     1       2010-10-10
000001     1       2010-10-11
000001     1       2010-10-12
000001     1       2010-10-13
000002     2       2010-10-10
000002     2       2010-10-11
000002     2       2010-10-12
000002     2       2010-10-13

Hay otrotb_shift tabla que contiene el tiempo de turno

CREATE TABLE `tb_shift` (
  `shiftcode` varchar(1) DEFAULT NULL,
  `shiftbegin2` varchar(4) DEFAULT NULL,
  `shiftbegin` varchar(4) DEFAULT NULL,
  `shiftmid` varchar(4) DEFAULT NULL,
  `shiftend` varchar(4) DEFAULT NULL,
  `shiftend2` varchar(4) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1

shiftcode   shiftbegin2  shiftbegin  shiftmid  shiftend  shiftend2
        1     04:00:00     08:00:00  12:00:00  17:30:00  21:30:00 
        2     12:00:00     17:30:00  21:00:00  05:30:00  09:30:00

Quiero determinar que cada día, si el empleado llega tarde al trabajo o sale temprano del trabajo, ya qué hora.

SELECT wdpercode,wddate,shiftbegin,shiftend,time(tlate.scscantime) wdlate,time(tearly.scscantime) wdearly
FROM tb_workday
LEFT JOIN tb_shift
  ON wdshift=shiftcode
LEFT JOIN tb_scan tlate 
  ON wdpercode=tlate.scpercode
  AND tlate.scyear=year(wddate)
  AND tlate.scmonth=month(wddate)
  AND (tlate.scday=day(wddate)
    OR tlate.scday=day(wddate)+1)
  AND tlate.scscantime>=ADDDATE(CONCAT(wddate,' ',shiftbegin),INTERVAL IF(shiftbegin2>shiftbegin,1,0) DAY)
  AND tlate.scscantime<=ADDDATE(CONCAT(wddate,' ',shiftmid),INTERVAL IF(shiftbegin2>shiftmid,1,0) DAY)
LEFT JOIN tb_scan tearly 
  ON wdpercode=tearly.scpercode
  AND tearly.scyear=year(wddate)
  AND tearly.scmonth=month(wddate)
  AND (tearly.scday=day(wddate)
    OR tearly.scday=day(wddate)+1)
  AND tearly.scscantime>ADDDATE(CONCAT(wddate,' ',shiftmid),INTERVAL IF(shiftbegin2>shiftmid,1,0) DAY)
  AND tearly.scscantime<ADDDATE(CONCAT(wddate,' ',shiftend),INTERVAL IF(shiftbegin2>shiftend,1,0) DAY)

Aquí está el ejemplo de una salida:

wdpercode wddate      shiftbegin  shiftend  wdlate    wdearly
000001    2016-01-10  08:00:00    17:30:00  08:02:00  (null)
000001    2016-01-11  08:00:00    17:30:00  (null)    17:29:00
000002    2016-01-11  17:30:00    05:30:00  17:31:00  (null)
000002    2016-01-11  17:30:00    05:30:00  (null)    05:29:00

estaADDDATE(CONCAT(wddate,' ',shiftbegin),INTERVAL IF(shiftbegin2>shiftbegin,1,0) DAY) es para empleados que trabajan en turno de noche, por lo que tiene que agregar 1 día en el turno

El problema es si creo un índice parascscantime, MySQL se niega a usarlo para comparar (>=,<=,>,<) Por favor vea este hilo¿Por qué MySQL no utiliza un índice para una comparación mayor que?

Debido a esto, creé elscyear, scmonthyscday campos y combinarlos en un índice junto conscpercode. Y tengo que asegurarme de que también se calcule para los trabajadores que trabajan en turno de noche, así que tengo que agregarlo conOR scday=day(wddate)+1 condición.

Antes de agregar la condición OR, elEXPLAIN El resultado fue de 52 filas. Pero cuando agregué elOR scday=day(wddate)+1 condición, elEXPLAIN El resultado se convirtió en 364 filas, lo que significa que MySQL no usó parte scday del índice. ¿Hay alguna forma de usar todo el índice, por lo que elEXPLAIN resultado se vuelve más eficiente como 52 filas? También intenté eliminar el+1 parte y el resultado es también 52.

Respuestas a la pregunta(1)

Su respuesta a la pregunta