8 sql-server sql-server-2008-r2
我有一个奇怪的查询编译问题,很难重现。它只发生在高负载下,不能轻易重复。
问题是这个查询的查询计划只有在 A 和 B 上有 Seek Predicate!C 和 D 上的谓词是一个普通的谓词,所以这意味着 C 和 D 列上的搜索树没有被使用。
所有参数的数据类型都与列数据类型相匹配。
任何人都可以提供有关为什么会发生这种情况的任何提示吗?SQL 版本为 2008 R2 (SP1) - 10.50.2789.0 (X64)
对于参数化查询它不能只做两次搜索
WHERE A=@P1 AND B=@P2 AND C=@P3 AND D=@P5
Run Code Online (Sandbox Code Playgroud)
和
WHERE A=@P1 AND B=@P2 AND C=@P4 AND D=@P5
Run Code Online (Sandbox Code Playgroud)
因为如果@P3 = @P4
那会错误地带回重复的行。所以它需要一个首先从这些中删除重复项的操作员。
从这个快速测试来看,它似乎取决于表格的大小,无论你是否得到它。在下面的测试中,245
/ 246
rows 是计划之间的分界点(这也是将所有内容都放在一页上的索引与变成 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
Run Code Online (Sandbox Code Playgroud)
这个计划有一个A=1 AND B=2
带有残差谓词的搜索(C=@C1 OR C=@C2) AND D=5
在第二个计划中,额外的操作员负责@C1,@C2
在执行搜索之前从第一个中删除任何重复项。
第二个计划中的搜索实际上是在A=1 AND B=2 AND C > Expr1010
和之间的范围搜索,并A=1 AND B=2 AND C < Expr1011
带有残差谓词 on 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
Run Code Online (Sandbox Code Playgroud)
但实际上在这个测试案例中,它可能会适得其反,因为对单页索引进行两次查找而不是一次查找会增加逻辑 IO。