Повышение производительности SQL-запросов
Sql:
select distinct DateAdd(Day, DateDiff(Day, 0, m.Receive_date), 0) as Date,
(select count(*) from Raw_Mats A where DateAdd(Day, DateDiff(Day, 0, A.Receive_date), 0)=DateAdd(Day, DateDiff(Day, 0, m.Receive_date), 0)) as Total,
(select count(*) from Raw_Mats B where DateAdd(Day, DateDiff(Day, 0, B.Receive_date), 0)=DateAdd(Day, DateDiff(Day, 0, m.Receive_date), 0) and B.status='Solved') as Delivered,
(select count(*) from Raw_Mats C where DateAdd(Day, DateDiff(Day, 0, C.Receive_date), 0)=DateAdd(Day, DateDiff(Day, 0, m.Receive_date), 0) and C.status='Pending') as UnDelivered
from Raw_Mats m where m.Receive_date between '2011-07-01' and '2011-07-21'
Как повысить производительность вышеуказанного запроса. Это займет 44 секунды. хочу сделать это менее чем за 10 секунд
Спасибо
3 ответа
У вас есть индекс на оба Receive_date
а также status
? (не индекс по каждому, в сочетании)
Также:
- У вас есть 4 касания в таблице, что означает, что запрос будет масштабироваться как минимум O(4n). С помощью COUNT(CASE) вы можете удалить
Delivered
а такжеUnDelivered
подзапросы - Простой подзапрос подсчета тоже не нужен
- Вам нужно GROUP BY. ВАШЕ ОТЛИЧИЕ - это обходной путь для этого
- МЕЖДУ
>=
а также<=
что обычно не подходит для дат со временем
Я использовал подзапрос здесь для ясности, но это не имеет значения:
select
DateOnly as Date,
COUNT(*) AS Total,
COUNT(CASE WHEN status='Solved' THEN 1 END) AS Delivered,
COUNT(CASE WHEN status='Pending' THEN 1 END) AS UnDelivered
from
(
SELECT
DateAdd(Day, DateDiff(Day, 0, m.Receive_date), 0) as DateOnly,
status
FROM
Raw_Mats
WHERE
Receive_date >= '2011-07-01' AND Receive_date < '2011-07-21'
) T
GROUP BY
DateOnly
Редактировать, без подзапроса.
Я начал с подзапроса, потому что думал, что это будет сложнее, чем ожидалось, и не потрудился снять его...
select
DateAdd(Day, DateDiff(Day, 0, m.Receive_date), 0) as Date,
COUNT(*) AS Total,
COUNT(CASE WHEN status='Solved' THEN 1 END) AS Delivered,
COUNT(CASE WHEN status='Pending' THEN 1 END) AS UnDelivered
from
Raw_Mats
WHERE
Receive_date >= '2011-07-01' AND Receive_date < '2011-07-21'
GROUP BY
DateAdd(Day, DateDiff(Day, 0, m.Receive_date), 0)
Разделяй и властвуй: просто попробуйте каждую часть вашего sql как отдельное утверждение, и вы узнаете, какая часть медленная. Если у вас есть подвыборы и функции, есть хороший шанс, что серверу понадобятся временные таблицы для выполнения выбора, если у вас недостаточно памяти (или большой набор данных или настроенный сервер sql для этого), это временные объекты перемещаются на диск, что также замедляет работу.
Слишком много подзапросов, человек! Избавьтесь от некоторых из них, и это поможет. Также вы не должны использовать функции с обеих сторон в вашем sqls.
Например:
where DateAdd(Day, DateDiff(Day, 0, A.Receive_date), 0)=
DateAdd(Day, DateDiff(Day, 0, m.Receive_date), 0)
В этом конкретном случае движок БД должен будет пройти через все строки, чтобы оценить DateDiff(Day, 0, A.Receive_date) and DateAdd(Day, DateDiff(Day, 0, A.Receive_date), 0)
затем сравните его с правой частью, которая также является функцией! Это просто катастрофа.
Кроме того, у вас есть индексы на Receive_date
? Если не добавить это.