Rub*_*ben 5 sql-server execution-plan parameter sql-server-2016 where
我有一些查询需要获取 64 个以上的特定行,例如这个带有 65 个 ID 的示例。TableID 为主键,类型为 BigInt。
SELECT * FROM TableA
WHERE TableID IN (260905384, 260915601, 260929877, 260939625, 260939946, 261096977, 261147037, 261152934, 261163936, 261357728, 261369122, 261376714, 261454472, 261488500, 261527284, 261584786, 261619749, 261679560, 261777653, 261786639, 261795246, 261795810, 261803724, 261821199, 261824173, 261827397, 261840197, 261848595, 261874545, 261889122, 261889355, 261929793, 261953069, 262106609, 262134069, 262134088, 262339745, 262354363, 262360015, 262571936, 262586920, 262591486, 262663776, 262703601, 262746674, 262792439, 262801544, 262826561, 262933229, 262933270, 262947539, 262958110, 263021588, 263032875, 263037208, 263039292, 263045038, 263085369, 263089147, 263091427, 263097644, 263100021, 263103339, 263104396, 263956373)
Run Code Online (Sandbox Code Playgroud)
如果我检查执行计划,它使用主键,但它执行了 65 次并添加了 Constand Scan 和 Nested Loops 操作项。但是 - 如果我将参数数量减少到 64,那么它只直接执行 1 次而没有其他操作。
我可以看到,对于 65 个以上的参数,Seek Predicates 仅包含一个元素,如果参数数量为 64 或更少,则 Seek Predicates 直接包含所有元素。
当参数数量超过 64 时,是否可以避免 MSSQL 多次执行一个参数?
在小表上,差异并不大,但如果我将结果与其他表连接起来,读取数量差异就会变得巨大。
要使用 StackOverflow2013 数据库重现这一点,例如:
/* 63 rows: */
SELECT *
FROM dbo.Users
WHERE Id IN (-1,1,2,3,4,5,8,9,10,11,13,16,17,19,20,22,23,24,25,26,27,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50,51,52,55,56,57,58,59,60,61,62,63,64,67,68,70,71,72,73,75,76,77,78);
/* 64 rows: */
SELECT *
FROM dbo.Users
WHERE Id IN (-1,1,2,3,4,5,8,9,10,11,13,16,17,19,20,22,23,24,25,26,27,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50,51,52,55,56,57,58,59,60,61,62,63,64,67,68,70,71,72,73,75,76,77,78,79);
/* 65 rows: */
SELECT *
FROM dbo.Users
WHERE Id IN (-1,1,2,3,4,5,8,9,10,11,13,16,17,19,20,22,23,24,25,26,27,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50,51,52,55,56,57,58,59,60,61,62,63,64,67,68,70,71,72,73,75,76,77,78,79,80);
GO
Run Code Online (Sandbox Code Playgroud)
前两个的实际执行计划只显示了聚集索引查找,但第三个添加了恒定扫描,并且估计的行数突然不正确:
在这个例子中,没有连接。但是,您可以想象,当您加入其他表时,这种不正确的估计可能会导致表扫描与索引查找 + 键查找之间的差异,并且使用低球估计,可能会选择不正确的索引查找 + 键查找计划其他表。
一个IN
子句被“重写”为这种形式,本质上:
WHERE
TableID = 260905384
OR TableID = 260915601
OR TableID = 260929877
...
Run Code Online (Sandbox Code Playgroud)
我听说并观察到 SQL Server 有 64 个OR
谓词的硬编码限制,它将放入扫描或搜索运算符。据我所知,这在任何地方都没有公开记录,而且我也没有任何方法可以改变它。
OR
正如您所提到的,除了 64 个表达式之外,您最终会得到“常量扫描”计划,该计划将多个搜索或扫描驱动到索引中(每个文字一个)。
将这么多值字面值放在一个IN
构造中通常被认为是一个坏主意。如果可能,请更改查询的编写方式。例如,您可以将所有这些值插入到临时表中,然后INNER JOIN
对该TableID
列上的临时表执行操作。
归档时间: |
|
查看次数: |
97 次 |
最近记录: |