SQL小提琴:http://sqlfiddle.com/#!3/23cf8
在此查询中,当我在Id上有In
子句,然后还选择其他列时,首先评估In,然后通过RID Lookup引入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 Lookup?
通过查看实际执行计划中的运营成本,我相信如果我可以让它使用RID查找,我可以将第二个查询的性能与第一个查询非常接近。如果我没有选择Detail
列,则两个查询的效果在生产中非常接近。只有在添加其他列(例如Detail
)之后,第二个查询的性能才会显着下降。当我把它放在SQL Fiddle中并看到执行计划使用了RID Lookup时,我感到很惊讶但有点困惑......
它没有聚集索引,因为在使用不同的聚簇索引进行测试时,此查询和其他查询的性能稍差。那是在我开始添加像Details
之类的其他专栏之前,我可以尝试更多,但是我希望能够在我开始在黑暗中随机索引拍摄之前了解现在发生的事情。
答案 0 :(得分:2)
如果要更改主索引以包含Details
列?
如果您使用:
CREATE NONCLUSTERED INDEX [IX_SupportContacts_ForeignIdAsc_IdDesc]
ON SupportContacts ([ForeignId] ASC, [Id] DESC)
INCLUDE (Details);
然后既不需要RID查找也不需要表扫描,因为您的查询只能从索引本身得到满足....
答案 1 :(得分:1)
查询计划的差异将取决于存在的索引类型以及不同环境中这些表的数据统计信息。
优化器使用统计数据(主要是数据频率的直方图)和可用的索引来决定哪个执行计划最快。
因此,例如,您注意到包含“详细信息”列时性能会下降。这几乎可以肯定,“详细信息”列不是索引的一部分,或者如果它是索引的一部分,该列中的数据大多是唯一的,因此索引访问将是等效的(或几乎等效)到桌面扫描。
通常在出现这种情况时,优化器将选择对索引访问进行表扫描,因为它可以利用块读取等方式来访问表记录,而不是对索引进行碎片读取。
要影响优化器将选择的路径,您需要查看可以添加/修改的可能索引以使索引访问更有效,但这应该小心,因为它可能会对其他方面产生负面影响查询以及可能降低插入性能。
您可以做的另一项重要活动是确保表格统计数据保持最新,并以适合表格数据中频率分布变化率的频率刷新
答案 2 :(得分:1)
如果使用相关索引+ RID执行查询,99%的行是否会被省略,那么生产环境中最有可能的问题是您的统计信息已过时且优化器没有意识到(1,2,3,5)中的ForeignID会将结果集限制为总数据的1%。
以下是发现Pinal Dave统计数据的更多链接:http://blog.sqlauthority.com/2010/01/25/sql-server-find-statistics-update-date-update-statistics/
至于强制优化器遵循正确的路径而不更新统计信息,您可以使用表提示 - 如果您知道您的计划应该使用的索引包含ID和ForeignID列,那么请将其作为查询中的链接提示并强制SQL优化器使用索引:
http://msdn.microsoft.com/en-us/library/ms187373.aspx
仅供参考,如果您想从第二个查询中获得最佳性能,请使用此索引并避免您遇到的麻烦:
create index ix1 on SupportContacts(ForeignID, Id DESC) include (Details);