У меня есть база данных с курсами. Каждый курс содержит набор узлов, а некоторые узлы содержат набор ответов от студентов. Смотрит ответу таблица (упрощенный), как это:Ошибка производительности при выборе n новых строк в подзапросе
Ответ
id | courseId | nodeId | answer
------------------------------------------------
1 | 1 | 1 | <- text ->
2 | 2 | 2 | <- text ->
3 | 1 | 1 | <- text ->
4 | 1 | 3 | <- text ->
5 | 2 | 2 | <- text ->
.. | .. | .. | ..
Когда учитель открывает курс (т.е. courseId = 1) Я хочу, чтобы выбрать узел, который получил наибольшее количество ответов в последнее время. Я могу сделать это с помощью следующего запроса:
with Answers as
(
select top 50 id, nodeId from Answer A where courseId=1 order by id desc
)
select top 1 nodeId from Answers group by nodeId order by count(id) desc
или одинаково, используя этот запрос:
select top 1 nodeId from
(select top 50 id, nodeId from Answer A where courseId=1 order by id desc)
group by nodeId order by count(id) desc
В обоих querys новейшие 50 ответов (с самыми высокими идентификаторами) выбираются, а затем группируются по NodeId так Я могу выбрать тот, который имеет самую высокую частоту. Моя проблема, однако, в том, что запрос выполняется очень медленно. Если я выполняю только подзапрос, он занимает меньше секунды, и группировка 50 строк должна быть быстрой, но когда я запускаю весь запрос, это занимает около 10 секунд! Я предполагаю, что сервер sql сначала выбирает и группирует, а затем делает верхнюю часть 50 и первую 1, что в этом случае приводит к ужасной производительности.
Итак, как я могу переписать запрос как эффективный?
Какие индексы у вас есть на этом столе? Я бы рекомендовал иметь один составной индекс на '(course_id, id)'. Что касается вашего предположения о том, что делает сервер sql, испытайте это эмпирически, получив планы выполнения и сравнив их. Вы можете обнаружить, что существование внешнего запроса изменяет план внутренней части запроса.Вы также можете обнаружить, что добавление указанного индекса полностью изменяет план. – MatBailie