2016-12-07 3 views
1

У меня есть 2 запроса: один с TOP-предложением и один без него. Результат такой же, но тот, у кого предложение TOP значительно медленнее. Почему это так?TOP clause slowing down query

Сервер: Microsoft SQL Server 2008 R2 (SP2)

Запрос 1 - Regular

insert into #Buffer (details, persistentID, productID, [date]) 
select de.details, lg.databaseID % 1000, lg.productID, lg.readDateTime 
from Log lg with (nolock) 
join LogDetails de with (nolock) 
    on lg.logID = de.logID 
where @startDate <= readDateTime and readDateTime < @endDate 
  • процессорного времени: 173,640 мс
  • Прошедшее время: 34700 мс
  • Execution Plan

Запрос 2 - ТОП пункт

insert into #Buffer (details, persistentID, productID, [date]) 
select top (@count) de.details, lg.databaseID % 1000, lg.productID, lg.readDateTime 
from Log lg with (nolock) 
join LogDetails de with (nolock) 
    on lg.logID = de.logID 
where @startDate <= readDateTime and readDateTime < @endDate 

Примечание @count является размер результирующего набора.

  • процессорного времени: 92953 мс
  • Прошедшее время: 93,732 мс
  • Execution plan

Как ни странно, время ЦП Query 2 составляет половину запроса 1, и все же время, затраченное на Query 2, в 3 раза превышает время запроса Query 1.

+0

, так как сейчас приходится заказывать результаты – Lamak

+3

Вы посмотрели план выполнения? Я бы предположил, что запрос «TOP» не использует индекс, где выполняется другой запрос, – HoneyBadger

+1

@Lamak Будет ли это? Нет «order by», не будет ли он просто возвращать результаты «top» в любом порядке, в котором они входят (т.е. произвольно)? – HoneyBadger

ответ

2

Исходя из этого: Inside the Optimizer: Row Goals In Depth от Paul White

Когда вы представите запрос к SQLServer, он предполагает, вы будете потреблять все строки, полученные по запросу. несколько раз, когда вы приведете TOP и EXISTS операторов, SQL-сервер попытается найти первую строку как можно скорее, это несколько раз приведет к меньшему оптимальному плану. В вашем случае это приведет к плану вложенных циклов.

Вы можете спросить, почему эта строка Цель не может быть оптимизировано..Белоу является объяснением от Пола Уайта за то же самое.

Задачи, связанные с созданием оптимизированного плана запросов для запросов с ограничениями по строкам, сохраняя при этом хорошую общую производительность оптимизации для запросов с полным результатом, сложнее, чем просто заменить хеширование или объединение итераторов объединения с вложенными циклами. Было бы разумно просто обслуживать запросы с помощью TOP в корне плана, используя специальный код, предназначенный для распознавания конкретных сценариев. Однако в более общих случаях этот подход будет пропускать более широкие возможности для оптимизации плана.

Предложение TOP может быть указано несколько раз в нескольких местах в объявлении запроса: в самой внешней области (как в примере); в подзапросе; или в общем табличном выражении, все из которых могут быть произвольно сложными.Подсказка запроса FAST 'n' также может использоваться, чтобы попросить оптимизатора предпочесть план, который быстро создает первые «n» строки, но не ограничивает общее количество строк, возвращаемых в целом, как в случае с TOP. В качестве окончательного примера рассмотрим, что логическое полусоединение (например, подзапрос, введенный с EXISTS) разделяет общую тему: он должен быть оптимизирован для быстрого поиска первой соответствующей строки.

Оптимизатор запросов SQL Server обеспечивает способ удовлетворения всех этих требований путем введения концепции «цели строки», которая просто устанавливает ряд строк для «нацеливания» на конкретную точку плана.

Так что в вашем случае, чтобы преодолеть это ROWGOAL ограничение, вы можете переписать запрос, как показано ниже, с помощью подсказки

insert into #ViewCountBuffer (details, persistentID, productID, [date]) 
select top (@count) details, databaseID % 1000, productID, readDateTime 
from Log ld with (nolock) 
HASH join LogDetails de with (nolock) 
    on ld.logID = de.logID 
where @startDate <= readDateTime and readDateTime < @endDate 

Ниже, связанные темы на стек обмена на ту же тему, ..

https://dba.stackexchange.com/questions/157353/wrapping-query-in-if-exists-makes-it-very-slow

https://dba.stackexchange.com/questions/126235/if-exists-taking-longer-than-embedded-select-statement

https://dba.stackexchange.com/questions/24832/how-and-why-does-top-impact-an-execution-plan

+0

Я добавил 'option (hash join)' к запросу, который ускорил его, но в конечном итоге удалил предложение TOP –