При использовании OPTION (RECOMPILE)
SQL Server обычно может выполнять оптимизация встраивания параметров.
План, который он компилирует, предназначен для одноразового использования, поэтому он может прослушивать значения всех переменных и параметров и обрабатывать их как константы.
Тривиальный пример, показывающий оптимизацию внедрения параметров в действии и эффект присваивания переменной, приведен ниже (фактические планы выполнения не оцениваются).
DECLARE @A INT = 1,
@B INT = 2,
@C INT;
SELECT TOP (1) number FROM master..spt_values WHERE @A > @B;
SELECT TOP (1) number FROM master..spt_values WHERE @A > @B OPTION (RECOMPILE);
SELECT TOP (1) @C = number FROM master..spt_values WHERE @A > @B OPTION (RECOMPILE);
Планы на это ниже
![введите здесь описание изображения](https://i.stack.imgur.com/Ftxt3.png)
Обратите внимание, что средний даже не касается таблицы, поскольку SQL Server может сделать вывод во время компиляции, что @A > @B
не является true
. Но план 3 вернулся к включению таблицы в план, поскольку назначение переменной, очевидно, предотвращает эффект OPTION (RECOMPILE)
, показанный в плане 2.
(Кроме того, третий план на самом деле не в 4-5 раз дороже, чем первый. Назначение переменной также, похоже, подавляет обычную логику цели строки, когда затраты на сканирование индекса будут уменьшены, чтобы отразить TOP 1
)
В вашем хорошем плане @i
значение 156567
вставляется прямо в поиск в опорной части рекурсивного CTE, он возвращает 0 строк, поэтому рекурсивная часть не должна выполнять никакой работы.
![введите здесь описание изображения](https://i.stack.imgur.com/STORd.png)
В вашем плохом плане рекурсивный CTE полностью материализуется с 627 393 выполнениями рекурсивного поддерева, и, наконец, предикат применяется к результирующим 627 393 строкам (отбрасывая их все) в конце
![введите здесь описание изображения](https://i.stack.imgur.com/k6Jdl.png)
Я не уверен, почему SQL Server не может сбросить предикат с переменной. Вы не предоставили определения своих таблиц или представление с рекурсивным CTE. Существует аналогичная проблема с предикаты push, view и оконные функции.
Одним из решений было бы изменить представление на встроенную функцию с табличным значением, которая принимает параметр для mainid, а затем добавить его в предложение WHERE
в якорной части определения. Вместо того, чтобы полагаться на SQL Server, чтобы вытолкнуть предикат для вас.
person
Martin Smith
schedule
30.05.2017
OPTION (RECOMPILE)
. Вы можете изменитьdbo.tvw_AllProjectStructureParents_ChildView
на встроенный TVF и передать параметр, чтобы вообще не использоватьOPTION (RECOMPILE)
. - person Martin Smith   schedule 30.05.2017