什么是Key Lookup?

Key Lookups 可能会导致性能问题
性能调整查询时最容易修复的事情之一是 Key Lookups 或 RID Lookups。当查询优化器对特定表执行index seek并且该索引没有满足结果集所需的所有列时,就会出现key lookup运算符。 SQL Server 被迫使用主键返回聚集索引并检索满足请求所需的剩余列。 RID lookup是相同的操作,但在没有聚集索引的表(也称为堆)上执行。它使用row id 而不是主键来进行查找。
如您所见,这些可能非常昂贵,并且可能导致 I/O 和 CPU 的性能大幅下降。 想象一个每分钟运行数千次的查询,其中包括一个或多个键查找。 这可能会导致由这些额外读取产生的巨大开销,它会影响整体引擎性能。

让我们看一个例子。

demo.sql
1
2
3
4
SELECT [SalesOrderID],[CarrierTrackingNumber],[OrderQty],[ProductID],
[UnitPrice],[ModifiedDate]
FROM [AdventureWorks2014].[Sales].[SalesOrderDetail]
Where [ModifiedDate]> '2014/01/01' and [ProductID]=772

键查找运算符的成本是查询的 99%。 您可以看到它对 IX_SalesOrderDetail_ProductID 执行了索引查找,这非常有效,但是该索引没有满足查询所需的所有列。 然后优化器使用聚集索引 PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID 检索它需要的其他列。 您可以通过将鼠标悬停在查询计划窗口中的键查找上来查看它得到了什么。

Key 和 RID look ups 的好处是它们非常容易修复。 通过对非聚集索引 IX_SalesOrderDetail_ProductID 稍作修改,我们可以将查询计划从index seek和key lookup更改为非常小的索引查找。 我们所要做的就是重新创建该索引并将输出列表字段添加为该索引上的包含列。

demo.sql
1
2
3
4
5
CREATE NONCLUSTERED INDEX [IX_SalesOrderDetail_ProductID] 
ON [Sales].[SalesOrderDetail]([ProductID] ASC)
INCLUDE ([CarrierTrackingNumber],[UnitPrice], [ModifiedDate], [OrderQty])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = ON, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]

正如您所看到的,我们现在只有一个 Index Seek 和一个更有效的计划。

参考引用:

What’s a Key Lookup?
Eliminating bookmark (key/rid) lookups

作者

zhang

发布于

2022-07-11

更新于

2023-09-19

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×