2016-11-30 2 views
2

У меня есть запрос, который работает, но он медленный. Есть ли способ ускорить это? В основном у меня есть таблица с записями timecard, а затем вторая таблица с разбивкой по времени этой записи, связанная с TimecardID. Я ищу временные блоки, для которых нет сбоев. Я подумал, что если я сокращу критерии до двух месяцев, это ускорит его. Спасибо за вашу помощьОшибка скорости запроса с условием NOT EXISTS

SELECT * FROM Timecards 
WHERE NOT EXISTS (SELECT TimeCardID FROM TimecardBreakdown WHERE Timecards.ID = TimecardBreakdown.TimeCardID) 
AND Status <> 0 
AND DateIn >= CURRENT_DATE() - INTERVAL 2 MONTH 
+0

Лучше индексировать B или B + деревья в БД. –

+0

Как я могу это сделать? – user3338040

+1

Обычно при обращении за помощью требуется оптимизация запроса для включения полных определений соответствующих таблиц. Результат «EXPLAIN» для запроса также пригодится. –

ответ

2

Кажется, что вы хотите знать TimecardIDs, которые не существуют в таблице TimecardBreakdown, в этом случае вы можете использовать левое внешнее соединение.

SELECT a.* 
FROM Timecards a 
LEFT OUTER JOIN TimecardBreakdown b ON a.TimecardID = b.TimecardID 
WHERE b.TimecardID IS NULL 

Это позволит избавиться от подзапроса (что дорого) и использовать соединение (что более эффективно).

+0

Я использовал ваше решение. Большое спасибо за помощь. Работал потрясающе. Сверх быстрый. – user3338040

+0

Рад, что это помогло вам, спасибо за верх и ответ. :-) –

0

MySQL воняет, делая коррелированные подзапросы быстро. Попробуйте сделать ваши подзапросы независимыми и присоединиться к ним. Вы можете использовать шаблон LEFT JOIN ... IS NULL для замены WHERE NOT EXISTS.

SELECT tc.* 
    FROM Timecards tc 
    LEFT JOIN TimecardBreakdown tcb ON tc.ID = tcb.TimeCardId 
WHERE tc.DateIn >= CURRENT_DATE() - INTERVAL 2 MONTH 
    AND tc.Status <> 0 
    AND tcb.TimeCardId IS NULL 

Некоторые точки оптимизации.

Во-первых, если вы можете изменить tc.Status <> 0 на tc.Status > 0, он делает возможным сканирование диапазона индекса в этой колонке.

Во-вторых, когда вы оптимизируете вещи, SELECT * считается вредным. Вместо этого, если вы можете указать имена только тех столбцов, которые вам нужны, все будет быстрее. Сервер базы данных должен перебирать все данные, которые вы запрашиваете; он не может сказать, проигнорируете ли вы некоторые из них.

В-третьих, этому запросу будет помогать составной индекс на Timecards (DateIn, Status, ID). Этот составной индекс можно использовать для выполнения тяжелых условий выполнения условий запроса.

Это называется индекс покрытия; он содержит данные, необходимые для удовлетворения большей части вашего запроса. Если бы вы указали только столбец DateIn, тогда обработчик запроса должен был вернуться в основную таблицу, чтобы найти значения Status и ID. Когда эти столбцы появляются в индексе, это сохраняет дополнительную операцию.

Если у вас SELECT определенный набор столбцов, а не SELECT *, в том числе эти столбцы в индексе покрытия могут значительно повысить производительность запросов. Это одна из нескольких причин, по которой SELECT * считается вредным.

(. Некоторые марки и модели СУБД имеют способы задания списков столбцов проехаться по индексам без фактического их индексации MySQL требует индексировать их, но покрывающие индексы по-прежнему помогают.).

Прочитайте это: http://use-the-index-luke.com/

Смежные вопросы