Функції вікна викликають жахливий план виконання, коли викликаються з виду із зовнішнім параметризованим пунктом "де"


10

У мене це питання було давно, я знайшов рішення, яке мені підходило, і забув про нього.

Але зараз це питання щодо ТА, тому я готовий вирішити цю проблему.

Існує думка, що об'єднує кілька таблиць дуже просто (накази + рядки замовлення).

При запиті без 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м рядків.
  • Величезне приєднання.
  • Обчислення вікон для всіх partitions (близько 500k вікон).
  • 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 є первинним ключем? Типи даних відповідності стовпців та параметрів?
gbn

order_numberне є первинним ключем. Він int not nullз некластеризованим індексом на ньому в обох таблицях.
GSerg

5
У SQL Server 2005 виникли проблеми з натисканням предикатів у цій галузі. Я думав, вони зараз виправлені. BTW у вашому прикладі TSQL використовує змінну, а не параметр. Чи додає OPTION (RECOMPILE)допомога?
Мартін Сміт

1
@GSerg - Тож у випадку поганого плану з останнім фільтром у фільтр передбачено 5 мільйонів рядків і приблизно 10 рядків, що відповідають фактичному? Якщо так, можливо, це те, що проблема просування предиката все ще не виправлена ​​повністю.
Мартін Сміт

Відповіді:


5

Це, здається, є давньою проблемою, яка продовжує формуватися в тій чи іншій формі і все ще присутня в SQL Server 2012.

Деякі публікації, що обговорюють це

Усі поточні версії SQL Server до 2012 року, включаючи 2012 рік, не в змозі натиснути фільтр на групу розділів, яка проходить через проект послідовності для параметризованого предиката, за винятком випадків, якщо option(recompile)вони використовуються (якщо 2008+).

Альтернативою recompileнатяку було б переписати запит, щоб використовувати параметризований вбудований TVF, як запропонував @ a1ex07)


Так само було і в SQL Server 2014
Guillaume86

3

Я б спробував замінити представлення на таблицю, що використовується у Udf. Таким чином він спочатку буде фільтрувати записи, а потім застосувати функцію вікна. Ця функція може приймати параметр таблиці , так що ви можете передати кілька order_numberв нього


Ще одне рішення, так. Я не міг цього зробити, тому що не всі клієнти мали можливість споживати табличну функцію.
GSerg

Чому? Я не впевнений на 100%, але я думаю, що все, що вам потрібно, це трохи змінити запит на щось на кшталтSELECT * FROM my_funct(12345)
a1ex07

Однією з вимог було те, що запит використовується в кінцевих споживачах, що використовують Excel (тобто MS Query), і MS Query не дозволить вам це робити, принаймні у версіях до 2003 року.
GSerg

it will filter records first, and then apply window functionневірно. Не існує детермінованого наказу про страту
Рем Русану
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.