Как улучшить производительность по запросу NOT IN

У меня есть следующий запрос SQL.

SELECT em.employeeid, tsi.timestamp
FROM timesheet_temp_import tsi
JOIN employee emp ON emp.employeeid = tsi.credentialnumber
WHERE
tsi.masterentity = 'MASTER' AND
tsi.timestamp NOT IN
(
    SELECT ea.timestamp 
    FROM employee_attendance ea 
    WHERE 
    ea.employeeid = em.employeeid
    AND ea.timestamp =  tsi.timestamp
    AND ea.ismanual = 0
)
GROUP BY em.employeeid, tsi.timestamp

Этот запрос сравнивает таблицу импорта (с отметками времени сотрудника и посещаемости).

Иногда timesheet_temp_import содержит более 95 000 строк, и мой запрос должен показывать только новые временные метки для сотрудника. Если временная метка для сотрудника уже существует, я должен исключить ее.

Запрос работает, но занимает более 4 минут, поэтому я хочу знать, могу ли я улучшить NOT IN Заявление с другим, что может помочь мне сократить это время.

5 ответов

С помощью NOT EXISTS может помочь тебе

SELECT 
    em.employeeid,
    tsi.timestamp
    FROM timesheet_temp_import tsi
    join employee emp ON emp.employeeid = tsi.credentialnumber
    WHERE
    tsi.masterentity = 'MASTER' AND

    NOT EXISTS 
    (
        SELECT NULL  
        FROM employee_attendance ea 
        WHERE 
        ea.employeeid = em.employeeid
        AND ea.timestamp =  tsi.timestamp
        AND ea.ismanual = 0
    )
    GROUP BY 
    em.employeeid,
    tsi.timestamp

У вас есть этот запрос:

SELECT em.employeeid, tsi.timestamp
FROM timesheet_temp_import tsi JOIN
     employee emp
     ON emp.employeeid = tsi.credentialnumber
WHERE tsi.masterentity = 'MASTER' AND
      tsi.timestamp NOT IN (SELECT ea.timestamp 
                            FROM employee_attendance ea 
                            WHERE ea.employeeid = em.employeeid AND
                                  ea.timestamp =  tsi.timestamp AND
                                  ea.ismanual = 0
                           )
GROUP BY em.employeeid, tsi.timestamp;

Прежде чем переписать запрос (в отличие от его переформатирования;), я бы проверил индексы и логику. Это GROUP BY необходимо? То есть есть ли дубликаты, созданные внешним запросом? Я думаю, нет, но я не знаю ваших данных.

Во-вторых, вы хотите индексы. Я думаю следующие показатели: timesheet_temp_import(masterentity, credentialnumber, timestamp), employee(employeeid), employee_attendance(employeeid, timestamp, ismanual),

В-третьих, я бы спросил, есть ли у вас табели учета рабочего времени для неработающих. Я думаю, что вы можете избавиться от внешнего join, Итак, это может быть запрос, который вы хотите:

SELECT tsi.credentialnumber as employeeid, tsi.timestamp
FROM timesheet_temp_import tsi
WHERE tsi.masterentity = 'MASTER' AND
      tsi.timestamp NOT IN (SELECT ea.timestamp 
                            FROM employee_attendance ea 
                            WHERE ea.employeeid = tsi.credentialnumber AND
                                  ea.timestamp =  tsi.timestamp AND
                                  ea.ismanual = 0
                           );

Вы также можете получить незначительное улучшение, заменив NOT IN с NOT EXISTS,

Попробуйте это, и я думаю, вы имеете в виду emp

SELECT distinct tsi.credentialnumber, tsi.timestamp
  FROM timesheet_temp_import tsi
  JOIN employee emp 
    ON emp.employeeid = tsi.credentialnumber
   and tsi.masterentity = 'MASTER' 
  left join employee_attendance ea 
    on ea.employeeid = emp.employeeid
   AND ea.timestamp = tsi.timestamp
   AND ea.ismanual = 0
 where ea.employeeid is null

в зависимости от индексов это может быть быстрее

SELECT distinct tsi.credentialnumber, tsi.timestamp
  FROM timesheet_temp_import tsi
  JOIN employee emp 
    ON emp.employeeid = tsi.credentialnumber
   and tsi.masterentity = 'MASTER' 
  left join employee_attendance ea 
    on ea.employeeid = tsi.credentialnumber
   AND ea.timestamp = tsi.timestamp
   AND ea.ismanual = 0
 where ea.employeeid is null

Другой способ заключается в использовании except

select whatever
from wherever
where somefield in 
(select all potential values of that field
except
select the values you want to exlude)

Это логически эквивалентно not in, но быстрее.

Использование LEFT JOIN а также WHERE пункт для фильтрации вместо NOT IN:

SELECT 
    em.employeeid,
    tsi.timestamp
    FROM timesheet_temp_import tsi
    join employee emp ON emp.employeeid = tsi.credentialnumber
    left join 
    (
        SELECT ea.timestamp 
        FROM employee_attendance ea 
        WHERE 
        ea.employeeid = em.employeeid
        AND ea.timestamp =  tsi.timestamp
        AND ea.ismanual = 0
    ) t on t.timestamp = tsi.timestamp
    WHERE
    tsi.masterentity = 'MASTER' AND
    t.timestamp is null
    GROUP BY 
    em.employeeid,
    tsi.timestamp
Другие вопросы по тегам