RDS SQL Server - 专题分享 - 巧用执行计划缓存之Key Lookup

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS SQL Server,基础系列 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: # 背景引入 执行计划缓存是SQL Server内存管理中非常重要的特性,这篇文章是巧用执行计划缓存系列文章之四,探讨什么是Key Lookup操作,如何从执行计划缓存中发现Key Lookup问题,以及如何解决这个问题。 # 什么是Key Lookup Key Lookup操作是指执行计划通过表的索引查找字段列的书签查找方式。Key Lookup发生在当查询语句使用Index Se

背景引入

执行计划缓存是SQL Server内存管理中非常重要的特性,这篇文章是巧用执行计划缓存系列文章之四,探讨什么是Key Lookup操作,如何从执行计划缓存中发现Key Lookup问题,以及如何解决这个问题。

什么是Key Lookup

Key Lookup操作是指执行计划通过表的索引查找字段列的书签查找方式。Key Lookup发生在当查询语句使用Index Seek(或者Index Scan)的同时,又需要查找Index中没有完全包含的额外字段列,这时SQL Server必须回过头来获取额外的字段列的值。通常情况下Key Lookup操作是通过表聚集索引来查找字段列的值,因此,可能会导致昂贵的查询性能开销,在性能优化过程中,需要引起我们足够的重视。

如何发现Key Lookup

在性能优化过程中,执行计划中的Key Lookup操作是我们优化的重点之一,那么我们如何发现Key Lookup操作呢?本文介绍两种方法:
执行计划图形展示
执行计划缓存中查找

执行计划图形展示

SQL Server客户端工具SSMS可以图形化方式直观的展示执行计划图形,我们可以通过这个直观的做图来发现Key Lookup操作。比如,我们有如下查询语句,在执行之前,我们打开实际执行计划采集开关(可以使用快捷键CTRL + M)。

USE [AdventureWorks2008R2];
GO
 
SELECT 
    NationalIDNumber, 
    HireDate, 
    MaritalStatus
FROM HumanResources.Employee WITH(NOLOCK)
WHERE NationalIDNumber = N'519899904';
GO

语句执行完毕后,会有Execution Plan窗口,从这里我们可以很轻易的看到Key Lookup事件操作,将鼠标悬停在Key Lookup事件上,会有弹窗展示更为详细的信息。详情参见如下截图,我们可以看到Key Lookup的性能开销为50%,占了整个查询语句性能开销的一半。开销算是很高的了。
01.png

执行计划缓存中查找

我们除了可以通过执行计划图形展示的方式来发现Key Lookup操作以外,我们还可以查找执行计划缓存来让Key Lookup操作无所遁形。比如,下面截图中信息是刚才执行语句的执行计划缓存中Key Lookup操作的XML节点。
02.png

所以,我们只需要搜索执行计划缓存,就可以找出哪些执行过的语句使用了Key Lookup操作,就可以针对性的进行性能优化。查找执行计划缓存的方法如下:

;WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT  
        --T.C.query('.')
        database_name = T.C.value('(IndexScan/Object/@Database)[1]','sysname')
        ,Schema_name = T.C.value('(IndexScan/Object/@Schema)[1]','sysname')
        ,Table_name = T.C.value('(IndexScan/Object/@Table)[1]','sysname')
        ,Index_name = T.C.value('(IndexScan/Object/@Index)[1]','sysname')
        ,index_type = T.C.value('(IndexScan/Object/@IndexKind)[1]','sysname')
        ,sql_text = T.C.value('(../../../../@StatementText)[1]','nvarchar(max)')
        ,output_columns =STUFF(( SELECT DISTINCT ', ' + cr.n.value('(@Column)[1]', 'sysname') 
                            FROM T.C.nodes('../../OutputList/ColumnReference') as cr(n) 
                            FOR XML PATH('')
                            ), 1, 2, '' )
        ,seek_columns =STUFF(( SELECT DISTINCT ', ' + cr.n.value('(@Column)[1]', 'sysname') 
                            FROM T.C.nodes('IndexScan/SeekPredicates/SeekPredicateNew/SeekKeys/Prefix/RangeColumns/ColumnReference') as cr(n) 
                            FOR XML PATH('')
                            ), 1, 2, '' )
        ,Predicate = T.C.value('(IndexScan/SeekPredicates/SeekPredicateNew/SeekKeys/Prefix/RangeExpressions/ScalarOperator/@ScalarString)[1]', 'nvarchar(max)')
        --,cp.usecounts
        --,qp.query_plan
FROM sys.dm_exec_cached_plans AS cp 
    CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) as qp
    CROSS APPLY qp.query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple/QueryPlan/RelOp/NestedLoops/RelOp[IndexScan[@Lookup="1"] and IndexScan/Object[@Schema!="[sys]"]]') as T(C)
WHERE T.C.exist('../RelOp[IndexScan[@Lookup="1"] and IndexScan/Object[@Schema!="[sys]"]]') = 1

比如,刚才的执行语句就被抓出来了,展示如下截图:
03.png

解决Key Lookup问题

从以上的分析,我们知道了Key Lookup对性能的影响,以及如何发现Key Lookup操作的语句,接下来的任务就是如何解决Key Lookup问题了。通常我们有如下方法:
删除不必要字段列
创建覆盖索引

删除不必要的字段列

这个解决方法很好理解,因为使用Key Lookup操作的目的就是为了查找SELECT字句中的字段列,如果我们将业务不必要,或者可要可不需要的字段列删除的话,很可能SQL Server就不会再走Key Lookup操作了,因此也就解决了这个问题。一个非常典型的场景是,很多开发人员喜欢使用SELECT * FROM操作。最好的方式是显示罗列所有业务必须要使用的字段名字,而不是一股脑儿全部字段都查询出来。

创建覆盖索引

如果万一,SELECT中的所有字段都是你业务所必须的,无法删除的话,我们可以考试使用覆盖索引来解决Key Lookup问题,即创建索引的时候,使用INCLUDE字句将SELECT后的字段包含在其中(排除在ON字句中字段,比如这里的NationalIDNumber字段列)。比如,上面的查询语句,我们可以创建覆盖索引:

USE [AdventureWorks2008R2];
GO
  
CREATE NONCLUSTERED INDEX IX_NationalIDNumber_@HireDate_@MaritalStatus
ON HumanResources.Employee (NationalIDNumber)
INCLUDE(HireDate, MaritalStatus)
WITH(FILLFACTOR = 90, ONLINE = ON)

执行完毕后,再次执行该语句,查看执行计划,仅一个Index Seek,没有Key Lookup操作,说明这个问题已经得到了解决。详情参见以下截图:
04.png

友情提醒

如果使用SSMS查看执行SQL语句的实际执行计划,XML 中IndexScan节点的Lookup属性值为True,如下展示:

...
<IndexScan Lookup="true" Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" ForceScan="false" NoExpandHint="false">
...

而从执行计划缓存中获取到的IndexScan节点中Lookup属性值为1。如下展示:

...
<IndexScan Lookup="1" Ordered="1" ScanDirection="FORWARD" ForcedIndex="0" ForceSeek="0" ForceScan="0" NoExpandHint="0">
...

因此,我们在分析执行计划缓存中的Key Lookup操作的时候,需要检查Lookup的值是否是1,而不是检查它是否为true。以下是SSMS执行计划中的XML节点,Lookup属性值为true,而在“执行计划缓存中查找”章节中的截图,我们知道Lookup属性值为1。
05.png

最后总结

这篇文章讨论了在性能优化过程中经常要遇到的一个需要优化的点叫Key Lookup操作,以及我们如何发现Key Lookup,最后谈到了两种解决Key Lookup问题的方法。

引用文章

Finding Key Lookups inside the Plan Cache

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2天前
|
SQL 存储 关系型数据库
MySQL/SqlServer跨服务器增删改查(CRUD)的一种方法
通过上述方法,MySQL和SQL Server均能够实现跨服务器的增删改查操作。MySQL通过联邦存储引擎提供了直接的跨服务器表访问,而SQL Server通过链接服务器和分布式查询实现了灵活的跨服务器数据操作。这些技术为分布式数据库管理提供了强大的支持,能够满足复杂的数据操作需求。
24 12
|
1月前
|
SQL 缓存 关系型数据库
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴因未能系统梳理MySQL缓存机制而在美团面试中失利。为此,尼恩对MySQL的缓存机制进行了系统化梳理,包括一级缓存(InnoDB缓存)和二级缓存(查询缓存)。同时,他还将这些知识点整理进《尼恩Java面试宝典PDF》V175版本,帮助大家提升技术水平,顺利通过面试。更多技术资料请关注公号【技术自由圈】。
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
|
1月前
|
SQL 开发框架 .NET
突破T-SQL限制:利用CLR集成扩展RDS SQL Server的功能边界
CLR集成为SQL Server提供了强大的扩展能力,突破了T-SQL的限制,极大地拓展了SQL 的应用场景,如:复杂字符串处理、高性能计算、图像处理、机器学习集成、自定义加密解密等,使开发人员能够利用 .NET Framework的丰富功能来处理复杂的数据库任务。
|
1月前
|
缓存 NoSQL 关系型数据库
mysql和缓存一致性问题
本文介绍了五种常见的MySQL与Redis数据同步方法:1. 双写一致性,2. 延迟双删策略,3. 订阅发布模式(使用消息队列),4. 基于事件的缓存更新,5. 缓存预热。每种方法的实现步骤、优缺点均有详细说明。
|
3月前
|
SQL 关系型数据库 MySQL
创建包含MySQL和SQLServer数据库所有字段类型的表的方法
创建一个既包含MySQL又包含SQL Server所有字段类型的表是一个复杂的任务,需要仔细地比较和转换数据类型。通过上述方法,可以在两个数据库系统之间建立起相互兼容的数据结构,为数据迁移和同步提供便利。这一过程不仅要考虑数据类型的直接对应,还要注意特定数据类型在不同系统中的表现差异,确保数据的一致性和完整性。
41 4
|
3月前
|
缓存 NoSQL 关系型数据库
MySQL与Redis缓存一致性的实现与挑战
在现代软件开发中,MySQL作为关系型数据库管理系统,广泛应用于数据存储;而Redis则以其高性能的内存数据结构存储特性,常被用作缓存层来提升数据访问速度。然而,当MySQL与Redis结合使用时,确保两者之间的数据一致性成为了一个重要且复杂的挑战。本文将从技术角度分享MySQL与Redis缓存一致性的实现方法及其面临的挑战。
161 2
|
3月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
4月前
|
缓存 NoSQL 算法
【Azure Redis 缓存】Redis性能指标之Server Load
【Azure Redis 缓存】Redis性能指标之Server Load
|
4月前
|
SQL 关系型数据库 数据库
数据库空间之谜:彻底解决RDS for SQL Server的空间难题
【8月更文挑战第16天】在管理阿里云RDS for SQL Server时,合理排查与解决空间问题是确保数据库性能稳定的关键。常见问题包括数据文件增长、日志文件膨胀及索引碎片累积。利用SQL Server的动态管理视图(DMV)可有效监测文件使用情况、日志空间及索引碎片化程度。例如,使用`sp_spaceused`检查文件使用量,`sys.dm_db_log_space_usage`监控日志空间,`sys.dm_db_index_physical_stats`识别索引碎片。同时,合理的备份策略和文件组设置也有助于优化空间使用,确保数据库高效运行。
116 2
|
4月前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。