У меня была эта проблема давным-давно, я нашел обходной путь, который подходил мне, и забыл об этом.
Но теперь есть такой вопрос о SO, поэтому я хочу поднять эту проблему.
Есть представление, которое соединяет несколько таблиц очень простым способом (заказы + строки заказа).
При запросе без where
предложения представление возвращает несколько миллионов строк.
Тем не менее, никто никогда не называет это так. Обычный запрос
select * from that_nasty_view where order_number = 123456;
Это возвращает около 10 записей из 5 миллионов.
Важная вещь: представление содержит оконную функцию, rank()
которая разделена точно полем, с помощью которого представление всегда запрашивается:
rank() over (partition by order_number order by detail_line_number)
Теперь, если это представление запрашивается с литеральными параметрами в строке запроса, точно так, как показано выше, он мгновенно возвращает строки. План выполнения в порядке:
- Поиск индекса по обеим таблицам с использованием индексов
order_number
(возвращает 10 строк). - Расчет окон по возвращенному крошечному результату.
- Выбор.
Однако, когда представление вызывается параметризованным способом, все становится неприятным:
Index scan
на всех столах игнорируя индексы. Возвращает 5м строк.- Огромное присоединение.
- Расчет окон по всем
partition
s (около 500 тыс. Окон). Filter
взять 10 рядов из 5м.- Выбрать
Это происходит во всех случаях, когда задействованы параметры. Это может быть SSMS:
declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;
Это может быть клиент ODBC, например Excel:
select * from that_nasty_view where order_number = ?
Или это может быть любой другой клиент, который использует параметры, а не SQL-конкатенацию.
Если оконная функция удалена из представления, она работает идеально быстро, независимо от того, запрашиваются ли ее параметры.
Мой обходной путь состоял в том, чтобы удалить нарушающую функцию и повторно применить ее на более позднем этапе.
Но что дает? Действительно ли это ошибка в работе SQL Server 2008 с оконными функциями?
order_number
не первичный ключ. Это int not null
с некластеризованным индексом в обеих таблицах.
OPTION (RECOMPILE)
?