SQL Параметризованный запрос сервера не использует некластеризованную фильтрацию - PullRequest
0 голосов
/ 08 мая 2020

Я определил некластеризованный индекс с помощью таблицы «Включить и отфильтровать по студентам». Версия сервера SQL - 2017.

Определение таблицы студентов:

CREATE TABLE [dbo].[Students]
(
    [Id] [INT] IDENTITY(1,1) NOT NULL,
    [Name] [NVARCHAR](50) NOT NULL,
    [CreatedOn] [DATETIME2](7) NOT NULL,
    [Active] [BIT] NOT NULL,
    [Deleted] [BIT] NOT NULL,

    CONSTRAINT [PK_Students] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]

Некластеризованный индекс с включением и фильтром:

CREATE NONCLUSTERED INDEX [NonClusteredIndex-20200508-225254] 
ON [dbo].[Students] ([CreatedOn] ASC)
INCLUDE([Name]) 
WHERE ([Active] = (1) AND [Deleted] = (0))
ON [PRIMARY]
GO

Этот запрос использует NonClusteredIndex -20200508-225254

SELECT Name, CreatedOn FROM dbo.Students
WHERE Active = 1
  AND Deleted = 0
ORDER BY CreatedOn

Фактический план выполнения

enter image description here

Но когда я использую параметризованный запрос, как показано ниже, он не t используйте NonClusteredIndex-20200508-225254. Почему так происходит? Где я ошибаюсь?

DECLARE @Active BIT = 1
DECLARE @Deleted BIT = 0

SELECT Name, CreatedOn 
FROM dbo.Students
WHERE Active = @Active
  AND Deleted = @Deleted
ORDER BY CreatedOn

Фактический план выполнения

enter image description here

1 Ответ

1 голос
/ 08 мая 2020

Это вполне ожидаемо.

Когда вы составляете план с параметрами или переменными, он должен создать план, который будет работать для любого возможного значения, которое они могут иметь.

Вы можете добавить OPTION (RECOMPILE) в инструкцию, чтобы их значения во время выполнения учитывались (в основном они заменяются литералами со значением времени выполнения), но это будет означать перекомпиляцию при каждом выполнении.

Вероятно, вам лучше всего иметь два отдельных запроса , один для случая, обрабатываемого отфильтрованным индексом, и один для других случаев.

Вы могли надеяться, что SQL Сервер сделает что-то подобное ниже и динамически переключится между сканированием кластерного индекса + сортировкой и сканирование отфильтрованного индекса и отсутствие сортировки (фильтры имеют предикаты запуска, поэтому выполняется не более одной ветви)

enter image description here

Но для получения этого плана необходимо было изменить отфильтрованный индекс для перемещения Name в ключевые столбцы, как показано ниже ...

CREATE NONCLUSTERED INDEX [NonClusteredIndex-20200508-225254] 
ON [dbo].[Students] ([CreatedOn] ASC, [Name] asc)
WHERE ([Active] = (1) AND [Deleted] = (0))

... и переписывание запроса t о

DECLARE @Active BIT = 1
DECLARE @Deleted BIT = 0

SELECT NAME,
       CreatedOn
FROM   dbo.Students WITH (INDEX =[NonClusteredIndex-20200508-225254])
WHERE  Active = 1
       AND Deleted = 0
       AND 1 = 1 /*Prevent auto parameterisation*/
       AND ( @Active = 1 AND @Deleted = 0 )
UNION ALL
SELECT NAME,
       CreatedOn
FROM   dbo.Students
WHERE  Active = @Active
       AND Deleted = @Deleted
       AND NOT ( @Active = 1
                 AND @Deleted = 0 )
ORDER  BY CreatedOn
OPTION (MERGE UNION) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...