对于参数化查询,不能只对它执行两次搜索
WHERE A=@P1 AND B=@P2 AND C=@P3 AND D=@P5
和
WHERE A=@P1 AND B=@P2 AND C=@P4 AND D=@P5
因为如果@P3 = @P4
那样会错误地带回重复的行。因此,将需要一个操作员首先从这些操作中删除重复项。
从快速测试的角度来看,这是否取决于表的大小。在下面的测试中,245
/ 246
行是计划之间的截止点(这也是索引适合一页上的所有索引,然后变为2个叶页和一个根页之间的截止点)。
CREATE TABLE T(A INT,B INT,C INT,D INT)
INSERT INTO T
SELECT TOP (245) 1,2,3,5
FROM master..spt_values v1
CREATE CLUSTERED INDEX IX ON T(A, B, C, D)
SELECT index_level,page_count, record_count
FROM sys.dm_db_index_physical_stats(db_id(),object_id('T'),1,NULL, 'DETAILED')
DECLARE @C1 INT = 3,
@C2 INT = 4
SELECT * FROM T WHERE A=1 AND B=2 AND (C=@C1 OR C=@C2) AND D=5
DROP TABLE T
1页/ 245行
该计划寻求A=1 AND B=2
一个带有剩余谓词的(C=@C1 OR C=@C2) AND D=5
2页/ 246行
在第二个计划中,额外的运算符负责@C1,@C2
在执行查找之前从第一个中删除任何重复项。
第二个计划中的搜索实际上是介于A=1 AND B=2 AND C > Expr1010
且A=1 AND B=2 AND C < Expr1011
带有剩余谓词的范围搜索D=5
。这仍然不是所有4列上的均等搜索。有关其他计划运营商的更多信息,请参见此处。
添加OPTION (RECOMPILE)
确实允许它在编译时检查参数值是否重复,并生成具有两个相等查找的计划。
您也可以使用
;WITH CTE
AS (SELECT DISTINCT ( C )
FROM (VALUES (@C1),
(@C2)) V(C))
SELECT CA.*
FROM CTE
CROSS APPLY (SELECT *
FROM T
WHERE A=1 AND B=2 AND D=5 AND C = CTE.C) CA
但是实际上,在此测试用例中,它可能会适得其反,因为在单页索引中有两次查找,而不是一次增加逻辑IO。
OPTION (RECOMPILE)
吗?