(Питання переміщено з SO)
У мене є таблиця (фіктивних даних) з кластерним індексом, що містить 2 стовпці:
Тепер я запускаю ці два запити:
declare
@productid int =1 ,
@priceid int = 1
SELECT productid,
t.priceID
FROM Transactions AS t
WHERE (productID = @productid OR @productid IS NULL)
AND (priceid = @priceid OR @priceid IS NULL)
SELECT productid,
t.priceID
FROM Transactions AS t
WHERE (productID = @productid)
AND (priceid = @priceid)
Фактичний план виконання обох запитів:
Як бачите, перший використовує SCAN, а другий - SEEK.
Однак, додавши OPTION (RECOMPILE)
до першого запиту, план виконання також склав SEEK:
Друзі з чату DBA сказали мені, що:
У вашому запиті @ productid = 1, що означає, що (productID = @ productID АБО @productID НУЛЬНИЙ) можна спростити до (productID = @ productID). Перший вимагає сканування для роботи з будь-яким значенням @productID, другий може використовувати пошук. Отже, використовуючи RECOMPILE, SQL Server вивчить, яке значення ви насправді маєте у @productID, і складе найкращий план для цього. З ненульовим значенням у @productID найкраще шукати. Якщо значення @productID невідоме, план повинен відповідати будь-якому можливому значенню в @productID, яке вимагало б сканування. Будьте попереджені: OPTION (RECOMPILE) примушує перекомпілювати план кожен раз, коли ви його запускаєте, що додасть кілька мілісекунд до кожного виконання. Хоча це лише проблема, якщо запит працює дуже часто.
Також:
Якщо @productID недійсний, до якого значення ви б шукали? Відповідь: ні до чого прагнути. Усі значення відповідають вимогам.
Я розумію, що OPTION (RECOMPILE)
змушує SQL Server бачити, які фактичні значення має параметри, і бачити, чи може він ШЕКНУТИ з ним.
Але зараз я втрачаю вигоду від попередньої компіляції.
Питання
IMHO - SCAN відбудеться лише в тому випадку, якщо параметр є нульовим.
Це добре - нехай SQL SERVER створить план виконання для SCAN.
АЛЕ, якщо SQL Server бачить, що я виконую цей запит багато разів зі значеннями: 1,1
тоді чому він не створює ДРУГИЙ план виконання та не використовує SEEK для цього
AFAIK - SQL створює план виконання для найбільш звернених запитів .
Чому SQL SERVER не зберігає план виконання для:
@productid int =1 , @priceid int = 1
(Я запускаю його багато разів із цими значеннями)
- Чи можна змусити SQL утримувати той план виконання (який використовує SEEK) - для майбутнього виклику?