SQL 小提琴:http ://sqlfiddle.com/#!3/23cf8
在此查询中,当我In
在 Id 上有一个子句,然后还选择其他列时,首先评估 In,然后通过 RID 查找拉入 Details 列和其他列:
--In production and in SQL Fiddle, Details is grabbed via a RID Lookup after the In clause is evaluated
SELECT [Id]
,[ForeignId]
,Details
--Generate a numbering(starting at 1)
--,Row_Number() Over(Partition By ForeignId Order By Id Desc) as ContactNumber --Desc because older posts should be numbered last
FROM SupportContacts
Where foreignId In (1,2,3,5)
使用此查询,将通过表扫描获取详细信息。
With NumberedContacts AS
(
SELECT [Id]
,[ForeignId]
--Generate a numbering(starting at 1)
,Row_Number() Over(Partition By ForeignId Order By Id Desc) as ContactNumber --Desc because older posts should be numbered last
FROM SupportContacts
Where ForeignId In (1,2,3,5)
)
Select nc.[Id]
,nc.[ForeignId]
,sc.[Details]
From NumberedContacts nc
Inner Join SupportContacts sc on nc.Id = sc.Id
Where nc.ContactNumber <= 2 --Only grab the last 2 contacts per ForeignId
;
在 SqlFiddle 中,第二个查询实际上获得了 RID 查找,而在具有一百万条记录的生产环境中,它产生了表扫描(该IN
子句消除了 99% 的行)
否则,SQL Fiddle 中显示的查询计划是相同的,唯一的区别是对于第二个查询,SQL Fiddle 中的 RID 查找是生产中的表扫描:(
我想了解导致这种行为的可能性?你会看什么样的东西来帮助确定它在这里使用表扫描的原因?
我如何影响它在那里使用 RID 查找?
从实际执行计划中的操作成本来看,如果我可以使用 RID 查找,我相信我可以让第二个查询在性能上非常接近第一个查询。如果我不选择该Detail
列,那么这两个查询的性能在生产中非常接近。只有在添加其他列之后Detail
,第二个查询的性能才会显着下降。当我把它放在 SQL Fiddle 中,看到执行计划使用了 RID Lookup 时,我很惊讶,但有点困惑......
它没有聚集索引,因为在使用不同聚集索引进行测试时,此查询和其他查询的性能稍差。那是在我开始添加其他列之前Details
,我可以尝试更多,但是想在我开始在黑暗中使用随机索引拍摄之前了解现在发生了什么。