Gre*_*reg 7 index sql-server hints filtered-index
我从其他问题和帖子中知道,当 SQL 编译查询计划时,它只能使用过滤索引,前提是保证每次查询运行时都可以使用过滤索引。这意味着您不能在 where 子句中使用变量,因为有时它可能能够使用过滤索引,有时则不能。
解决此问题的一种方法是使用OPTION(RECOMPILE)
,以便它可以使用它的次数,它将获得过滤后的索引。
做一些测试,我发现这个查询可以使用过滤索引(注意,我强制使用索引只是为了证明一个观点):
SELECT MAX(table1.SomeDateField)
FROM dbo.table1 WITH(INDEX(MyFilteredIndex))
WHERE table1.filteredColumn = @variable
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
但是,如果我想将结果分配给一个变量,我就不走运了:
SELECT @OutputVariable = MAX(table1.SomeDateField)
FROM dbo.table1 WITH(INDEX(MyFilteredIndex))
WHERE table1.filteredColumn = @variable
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
结果是:
消息 8622,级别 16,状态 1,第 15 行 由于此查询中定义的提示,查询处理器无法生成查询计划。在不指定任何提示且不使用 SET FORCEPLAN 的情况下重新提交查询。
当我不想将输出保存到变量时,查询可以清楚地使用过滤后的索引,因为它运行 find 。
我有办法将此查询重写为硬编码@variable
以消除问题,但有人可以解释为什么第一个查询可以使用过滤索引,而第二个查询不能?
Jos*_*ell 12
允许您使用带有RECOMPILE
提示的过滤索引的优化称为“参数嵌入优化”。这是一个查询解析器用变量内的文字值替换变量引用的过程。
请参阅 Paul White 的这篇文章,了解它在您的第二种情况下不起作用的原因:参数嗅探、嵌入和重新编译选项
在一种情况下,使用
OPTION (RECOMPILE)
不会导致应用参数嵌入优化。如果语句分配给变量,则不会嵌入参数值:
这应该有效:
declare @myVariable int
declare @variable int = 9
declare @OutputVariable date
declare @t table(MaxDate date)
insert into @t(MaxDate)
SELECT MAX(table1.SomeDateField)
FROM dbo.table1 WITH(INDEX(MyFilteredIndex))
WHERE table1.filteredColumn = @variable
OPTION (RECOMPILE)
select @OutputVariable MaxDate from @t
Run Code Online (Sandbox Code Playgroud)
而且您始终可以使用带有文字值的动态 SQL,而不是尝试使用 OPTION (RECOMPILE) 将参数转换为文字。例如
declare @variable int = 9
declare @OutputVariable date
declare @sql nvarchar(max) = concat(N'
SELECT @OutputVariable = MAX(table1.SomeDateField)
FROM dbo.table1 WITH(INDEX(MyFilteredIndex))
WHERE table1.filteredColumn = ', @variable)
exec sp_executesql @sql, N'@OutputVariable date out', @OutputVariable = @OutputVariable out
select @OutputVariable
Run Code Online (Sandbox Code Playgroud)