SQL服务器参数化查询不使用非聚簇过滤
SQL Server parameterized query does not use Non Clustered Filtered
我在 Students table 上定义了一个包含和过滤的非聚簇索引。 SQL服务器版本是2017.
学生table定义:
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
实际执行计划
但是当我使用如下参数化查询时,它没有使用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
实际执行计划
这完全在意料之中。
当您编译带有参数或变量的计划时,它需要生成一个适用于它们可能具有的任何可能值的计划。
您可以将 OPTION (RECOMPILE)
添加到语句中,以便考虑这些的运行时值(基本上它们被替换为具有运行时值的文字)但这将意味着每次执行都要重新编译。
您最好有两个单独的查询,一个用于过滤索引处理的情况,一个用于其他情况。
您可能一直希望 SQL 服务器会执行类似下面的操作,并在聚集索引扫描 + 排序与过滤索引扫描和不排序之间动态切换(过滤器最多只有启动谓词)执行一个分支)
但是要获得此计划需要更改过滤索引以将 Name
移动到如下关键列中...
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20200508-225254]
ON [dbo].[Students] ([CreatedOn] ASC, [Name] asc)
WHERE ([Active] = (1) AND [Deleted] = (0))
...并将查询重写为
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)
我在 Students table 上定义了一个包含和过滤的非聚簇索引。 SQL服务器版本是2017.
学生table定义:
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
实际执行计划
但是当我使用如下参数化查询时,它没有使用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
实际执行计划
这完全在意料之中。
当您编译带有参数或变量的计划时,它需要生成一个适用于它们可能具有的任何可能值的计划。
您可以将 OPTION (RECOMPILE)
添加到语句中,以便考虑这些的运行时值(基本上它们被替换为具有运行时值的文字)但这将意味着每次执行都要重新编译。
您最好有两个单独的查询,一个用于过滤索引处理的情况,一个用于其他情况。
您可能一直希望 SQL 服务器会执行类似下面的操作,并在聚集索引扫描 + 排序与过滤索引扫描和不排序之间动态切换(过滤器最多只有启动谓词)执行一个分支)
但是要获得此计划需要更改过滤索引以将 Name
移动到如下关键列中...
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20200508-225254]
ON [dbo].[Students] ([CreatedOn] ASC, [Name] asc)
WHERE ([Active] = (1) AND [Deleted] = (0))
...并将查询重写为
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)