Как улучшить производительность по запросу 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