ВЫБРАТЬ ТОП медленно, независимо от ЗАКАЗА ПО - PullRequest
22 голосов
/ 09 июня 2011

У меня довольно сложный запрос в SQL Server, работающий с представлением, в форме:

SELECT *
   FROM myview, foo, bar 
   WHERE shared=1 AND [joins and other stuff]
   ORDER BY sortcode;

План запроса, как показано выше, показывает операцию Sort непосредственно перед финальной SELECT,чего я и ожидал.Есть только 35 совпадающих записей, и запрос занимает менее 2 секунд.

Но если я добавлю TOP 30, запрос займет почти 3 минуты!Использование SET ROWCOUNT столь же медленно.

Глядя на план запроса, теперь кажется, что он сортирует все 2+ миллиона записей в myview до объединений и фильтров.

Эта «сортировка» отображается в плане запроса в виде сканирования индекса по индексу sortcode, поиска по кластерному индексу в главной таблице и вложенного цикла между ними, все до объединений и фильтров.

Как заставить SQL Server SORT непосредственно перед TOP, как это происходит, когда TOP не указано?

Я не думаю, что создание myview является проблемой, но на всякий случай, это что-то вроде этого:

CREATE VIEW myview AS
   SELECT columns..., sortcode, 0 as shared FROM mytable
   UNION ALL
   SELECT columns..., sortcode, 1 as shared FROM [anotherdb].dbo.mytable

Локальный mytable имеет несколько тысяч записейи mytable в другой базе данных того же экземпляра MSSQL содержит несколько миллионов записей.Обе таблицы имеют индексы в соответствующем столбце sortcode.

1 Ответ

10 голосов
/ 09 июня 2011

И так начинается неудачная игра «попытаться перехитрить оптимизатор (потому что он не всегда знает лучше)».

Вы можете попробовать поместить фильтрующие части в подзапрос или CTE:

SELECT TOP 30 *
FROM
   (SELECT *
   FROM myview, foo, bar 
   WHERE shared=1 AND [joins and other stuff]) t
ORDER BY sortcode;

Этого может быть достаточно, чтобы сначала выполнить фильтрацию (но оптимизатор становится «умнее» с каждым выпуском и иногда может видеть через такие махинации).Или вам, возможно, придется пойти так далеко, чтобы поместить этот код в UDF .Если вы пишете UDF как многозначную табличную функцию с внутренней фильтрацией, а затем запрашиваете эту UDF с помощью TOP x / ORDER BY, вы довольно хорошо форсировали порядок запросов (поскольку SQL Server в настоящее время не можетоптимизация вокруг многоступенчатых UDF).


Конечно, если подумать, введение UDF - это просто способ скрыть то, что мы действительно делаем - создать временную таблицу, использовать один запрос для ее заполнения (на основе фильтров WHERE), затем другой запрос для поиска TOP x из временной таблицы.

...