У меня была эта проблема давным-давно, я нашел обходной путь, который подходил мне, и забыл об этом.
Но теперь есть такой вопрос о 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)
?Ответы:
Это, кажется, давняя проблема, которая постоянно обновляется в той или иной форме и все еще присутствует в SQL Server 2012.
Некоторые посты обсуждают это
Все текущие версии SQL Server до 2012 года включительно не могут использовать фильтр в группе секционирования после проекта последовательности для параметризованного предиката, кроме случаев
option(recompile)
использования (если 2008+).Альтернативой
recompile
подсказке было бы переписать запрос для использования параметризованного встроенного TVF, как предложено @ a1ex07)источник
Я бы попробовал заменить представление табличным udf. Таким образом, он будет сначала фильтровать записи, а затем применять оконную функцию. Эта функция может принимать параметр таблицы, так что вы можете передать
order_number
в нее несколько значенийисточник
SELECT * FROM my_funct(12345)
it will filter records first, and then apply window function
это неверно. Нет никакого детерминированного заказа к исполнению