我有一个与此类似的 T-SQL 查询(有点复杂,这里简化一下):
SELECT *
FROM ParticipantTable p
WHERE p.OrganizationId = @p__linq__0
AND p.ParticipantId IN (
@p__linq__1,
@p__linq__2,
@p__linq__3,
@p__linq__4,
@p__linq__5,
@p__linq__6,
@p__linq__7,
@p__linq__8,
@p__linq__9,
@p__linq__10
)
我对聚集索引查找执行大于/小于比较而不是每个输入键值的“正常”查找感到惊讶:
Seek Keys[1]: Prefix: [snip].OrganizationId = Scalar Operator([@p__linq__0]); Start: [snip].ParticipantId > Scalar Operator([Expr1031]); End: [snip].ParticipantId < Scalar Operator([Expr1032])
为什么?查找范围不是uniqueidentifier
非常低效吗?很容易导致选择非常广泛的值?循环遍历输入值并逐个查找不是更高效吗?或者,只有十个值,直接将值拉入查找运算符?
我猜这可能只是一种优化,因为所讨论的组织的参与者数量很少,但将值拉入查找运算符不是更合理吗?
另外,仅出于学术兴趣,有没有办法强制 SQL Server 根据值而不是范围进行搜索?WITH (FORCESEEK([snip](OrganizationId, ParticipantId))
不起作用,它仍将根据大于/小于进行搜索。我还添加了OPTIMIZE FOR UNKNOWN
,但没想到它在这里会做任何事情(而且它也没有)。
这就是它实际在做的事情。执行计划中显示的
>
和<
有点误导,是底层机制的产物,是用于多种情况的通用功能。它使用动态查找机制并传递一个标志
62
,告诉存储引擎进行相等查找。(即,从值 2 到 32 的所有五位(含)均按照前面的链接和我在此处的回答中的表格进行设置)
62
当查看连接和常量扫描运算符之间的计算标量的属性时,您会看到这一点。这里使用它来对参数化列表进行重复数据删除,然后对剩余的每个值进行查找(因为如果同一行在列表中出现
IN
多次,则多次返回同一行会出现错误)有关此执行计划模式的更多信息,请参阅动态查找和隐藏隐式转换