RDS SQL Server - 专题分享 - 巧用执行计划缓存之Single-used plans

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: # 背景引入 执行计划缓存是SQL Server内存管理中非常重要的特性,这篇系列文章我们探讨执行计划缓存设计中遇到的single-used plans问题,以及如何发现、如何定性和定量分析single-used plans带来的影响,最后我们使用两种方法来解决这个问题。 # 什么是Single-used Plans 要解释清楚什么是Single-used Plans,首先需要解释SQL语句

背景引入

执行计划缓存是SQL Server内存管理中非常重要的特性,这篇系列文章我们探讨执行计划缓存设计中遇到的single-used plans问题,以及如何发现、如何定性和定量分析single-used plans带来的影响,最后我们使用两种方法来解决这个问题。

什么是Single-used Plans

要解释清楚什么是Single-used Plans,首先需要解释SQL语句执行计划缓存是什么?SQL Server执行每一条SQL语句之前,会从执行计划缓存内存中查看是否存在本条语句的执行计划,如果不存在,会将其编译、选择最优路径、生成执行计划,然后会将执行计划存储在一块专门的内存区域中(这块内存叫着执行计划缓存),以供下次该语句执行直接从执行计划缓存中获取编译完毕的执行计划。以此来节约数据库系统对于查询语句编译、生成执行计划过程的性能开销,提高SQL语句的执行效率。
而Single-used Plans是指那些第一次执行后被缓存起来的执行计划,而后再也没有被重复利用过的执行计划缓存。其中ad hoc query(即席查询)就是典型的single-used plans中的一种。

如何发现Single-used Plans

从上一节我们可以大致知道,single-used plans仅会第一次被使用(从名字也可以很好理解到这一点),所以,实际上single-used plans是对SQL Server内存空间和CPU资源的浪费,对数据库性能有一定的损害。那么,我们如何来发现single-used plans呢?我们可以使用下面的查询语句:

USE master
GO

SELECT
    database_name = QUOTENAME(db.name),
    st.text,
    cp.objtype,
    cp.size_in_bytes,
    qp.query_plan,
    cp.cacheobjtype
FROM sys.dm_exec_cached_plans AS cp 
    CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
    INNER JOIN sys.databases AS db WITH(NOLOCK)
    ON st.dbid = db.database_id
    CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
WHERE cp.cacheobjtype = N'Compiled Plan'
AND cp.objtype IN (N'Adhoc', N'Prepared')
AND cp.usecounts = 1
ORDER BY cp.size_in_bytes DESC

我的测试实例展示的查询结果如下:
01.png

执行计划缓存中有多少Single-used Plans

当我们可以有效的发现single-used plans以后,我们可能又会问:到底我的SQL Server数据库实例中,有多少执行计划缓存是属于single-used plans类型呢?可以从两个维度来分析:
Single-used plans记录总数
Single-used plans总的执行计划占用的内存空间大小
可以使用以下的查询语句来回答这个问题。

USE master
GO
SELECT
    COUNT(1) AS [total_plans], 
    CAST(SUM(size_in_bytes)/1024. AS DECIMAL(18,2)) AS [total_size_in_kb], 
    CAST(SUM((CASE WHEN usecounts = 1 THEN size_in_bytes ELSE 0 END))/1024. AS DECIMAL(12,2)) AS [total_size_single_used_in_kb], 
    SUM(CASE WHEN usecounts = 1 THEN 1 ELSE 0 END) AS [total_plans_count_single_used],
    AVG(usecounts) AS [avg_used_counts], 
    CAST(AVG(size_in_bytes)/1024. AS DECIMAL(12, 2)) AS [avg_used_size_kb]
FROM sys.dm_exec_cached_plans WITH(NOLOCK)

我的测试实例执行结果如下截图:
02.png

从这个结果我们可以得出如下single-used plans的数据:总的single-used plans记录数为73,内存空间占用大小为13912 KB。

Single-used Plans对性能的影响

就单单一条Single-used Plan来看的话,对数据库系统的性能影响很小,小到可以忽略的地步,所以,数据库执行计划缓存中,存在少量的Single-used Plans是很正常的,可以不用太关注。但是,如果Single-used Plans大量存在的话,可能就会对系统带来比较严重的性能影响。

定性分析

定性分析大量Single-used Plans对数据性能的影响,主要体现在以下几个方面:
总的执行计划缓存利用率不高:因为存在大量不能被重复利用的执行计划缓存,从而拉低了执行计划缓存整体利用率
浪费执行计划缓存中内存的开销:每一条执行计划缓存或多或少会占用一定的执行计划缓存内存空间,大量的Single-used Plans导致了内存空间的浪费
导致CPU使用率的上升:每一条SQL语句执行计划的编译、最优路径选择和执行计划缓存,这些过程都需要消耗系统CPU资源,如果大量存在Single-used Plans,会导致系统CPU使用率的上升。
举一个最为极端的例子,假设执行计划缓存中存储的所有执行计划都是Single-used Plans的话,那么导致的严重后果是:
执行计划缓存利用率就是0%,因为没有任何的执行计划被重用
执行计划缓存这种设计就毫无意义,因为缓存起来也没有被重用
浪费执行计划缓存的内存开销和CPU开销

定量分析

以上是定性分析Single-used Plans对系统性能的影响,那么到底Single-used Plans达到哪个数量级,占比多少的时候,我们需要密切关注呢?虽然微软没有官方的推荐数字,但是个人比较推荐的两个数字是2GB和50%,即:所有的Single-used Plans使用的内存空间超过2GB或者内存空间使用占比超过50%。当然最终也可能取决于SQL Server可以使用的最大内存数量。

USE master
GO

IF OBJECT_ID('tempdb..#temp') IS NOT NULL
    DROP TABLE #temp

SELECT 
    objtype AS [cachetype], 
    COUNT(1) AS [total_plans], 
    CAST(SUM(size_in_bytes)/1024. AS DECIMAL(18,2)) AS [total_size_in_kb], 
    CAST(SUM((CASE WHEN usecounts = 1 THEN size_in_bytes ELSE 0 END))/1024. AS DECIMAL(12,2)) AS [total_size_single_used_in_kb], 
    SUM(CASE WHEN usecounts = 1 THEN 1 ELSE 0 END) AS [total_plans_count_single_used],
    AVG(usecounts) AS [avg_used_counts], 
    CAST(AVG(size_in_bytes)/1024. AS DECIMAL(12, 2)) AS [avg_used_size_kb]
INTO #temp
FROM sys.dm_exec_cached_plans WITH(NOLOCK)
GROUP BY objtype


SELECT 
    [cachetype],
    [total_plans],
    [total_size_in_kb],
    [total_plans_count_single_used],
    [total_size_single_used_in_kb],
    CAST(([total_plans_count_single_used]*1.0 / [total_plans]*1.0) * 100. AS DECIMAL(12, 2)) AS [single_used_plan_count%],
    CAST([total_size_single_used_in_kb]/[total_size_in_kb] * 100. AS DECIMAL(12, 2)) AS [single_used_size%],
    [avg_used_counts],
    [avg_used_size_kb]
FROM #temp
ORDER BY [total_size_single_used_in_kb] DESC


SELECT 
    SUM([total_plans]) AS total_plan_counts,
    SUM([total_size_in_kb]) AS total_plan_size_in_kb,
    SUM([total_plans_count_single_used]) AS [total_plans_counts_single_used],
    SUM([total_size_single_used_in_kb]) AS [total_plan_size_single_used_in_kb],
    CAST(SUM([total_plans_count_single_used]) * 100. / SUM([total_plans]) AS DECIMAL(12, 2)) AS [plan_counts_single_used%],
    CAST(SUM([total_size_single_used_in_kb]) * 100. / SUM([total_size_in_kb]) AS DECIMAL(12, 2)) AS [plan_size_single_used%]
FROM #temp

执行结果如下所示:
03.png

从这个执行结果来看,在我的SQL Server测试实例上,single-used plans占用的执行计划记录数为72条,内存空间占用14016 KB;single-used plans执行计划记录数占总的百分比为39.78%,内存空间占用比例为50.59%。

解决Single-used Plans问题

从定量分析小结,发现我的测试实例,single-used plans占用执行计划缓存内存比例已经超过50%了,是解决single-used plans问题的时候到了。

清空Single-used Plans

第一种方法是手动清理single-used plans,当然,你也可以很暴力的将所有执行计划缓存清空,从而也就清理了single-used plans,但是这样会误杀很多有用的无辜的执行计划缓存,从而导致这些执行计划重编译,影响性能。我们推荐使用下面的方法,仅清空哪些single-used plans,方法如下:

USE master
GO

DECLARE
    @plan_handle varbinary(64)
;

DECLARE
     cur_single_used_plan_handle CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT cp.plan_handle
FROM sys.dm_exec_cached_plans AS cp WITH(NOLOCK)
WHERE usecounts = 1

OPEN cur_single_used_plan_handle
FETCH NEXT FROM cur_single_used_plan_handle INTO @plan_handle
WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @plan_handle

    DBCC FREEPROCCACHE (@plan_handle); 

    FETCH NEXT FROM cur_single_used_plan_handle INTO @plan_handle
END

CLOSE cur_single_used_plan_handle
DEALLOCATE cur_single_used_plan_handle
GO

optimize for ad hoc workloads配置选项

除了手动清理single-used plans执行计划缓存外,另外一个更强大的功能是修改SQL Server 实例级别的配置选项optimize for ad hoc workloads。为了解决single-used plans带来的问题,微软从SQL Server 2008开始引入了这个全新选项,当打开这个选项以后,一个ad hoc的查询语句在第一次执行的时候,系统会创建一个“compiled plan stub”,并不会将执行计划缓存起来,只有当第二次该语句再被执行的时候,执行计划才会被缓存在内存中,从而避免了single-used plans带来的问题。配置这个选项的方法很简单,参见以下语句:

EXEC sys.sp_configure 'show advanced options', 1
RECONFIGURE
GO

EXEC sys.sp_configure 'optimize for ad hoc workloads', 1
RECONFIGURE
GO

最后总结

这篇文章讨论了执行计划缓存中的single-used plans带来的问题,如何发现,如何去定量和定性分析,以及最后怎么解决single-used plans的问题。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
4月前
|
SQL 存储 关系型数据库
RDS for MySQL的SQL分类与数据类型
小明需在MySQL中管理商品信息,使用SQL完成业务操作。SQL分为DQL(查询)、DML(增删改)、DDL(定义)、DCL(权限控制)和TCL(事务)五大类。DDL用于创建、修改和删除数据库结构,DML处理数据,DCL控制权限,TCL管理事务,DQL则用于查询数据。MySQL有多种数据类型,如数值型(整数、小数)、日期型和字符串型等,选择合适的数据类型是高效开发的关键。
52 0
|
24天前
|
缓存 NoSQL 算法
【Azure Redis 缓存】Redis性能指标之Server Load
【Azure Redis 缓存】Redis性能指标之Server Load
|
1月前
|
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`识别索引碎片。同时,合理的备份策略和文件组设置也有助于优化空间使用,确保数据库高效运行。
40 2
|
25天前
|
缓存 NoSQL 网络安全
【Azure Redis 缓存 Azure Cache For Redis】Redis性能问题,发现Server Load非常的高,导致正常连接/操作不成功
【Azure Redis 缓存 Azure Cache For Redis】Redis性能问题,发现Server Load非常的高,导致正常连接/操作不成功
|
2月前
|
关系型数据库 分布式数据库 数据库
PolarDB产品使用问题之将RDS切换到PolarDB-X 2.0时,代码层的SQL该如何改动
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
3月前
|
缓存 分布式计算 关系型数据库
数据管理DMS操作报错合集之当进行RDS实例的可用区迁移时,提示“缓存清理”是什么意思
数据管理DMS(Data Management Service)是阿里云提供的数据库管理和运维服务,它支持多种数据库类型,包括RDS、PolarDB、MongoDB等。在使用DMS进行数据库操作时,可能会遇到各种报错情况。以下是一些常见的DMS操作报错及其可能的原因与解决措施的合集。
|
4月前
|
SQL 关系型数据库 数据库
阿里云数据库 RDS SQL Server版实战【性能优化实践、优点探析】
本文探讨了Amazon RDS SQL Server版在云数据库中的优势,包括高可用性、可扩展性、管理便捷、安全性和成本效益。通过多可用区部署和自动备份,RDS确保数据安全和持久性,并支持自动扩展以适应流量波动。可视化管理界面简化了监控和操作,而数据加密和访问控制等功能保障了安全性。此外,弹性计费模式降低了运维成本。实战应用显示,RDS SQL Server版能有效助力企业在促销高峰期稳定系统并保障数据安全。阿里云的RDS SQL Server版还提供了弹性伸缩、自动备份恢复、安全性和高可用性功能,进一步优化性能和成本控制,并与AWS生态系统无缝集成,支持多种开发语言和框架。
296 2
|
4月前
|
安全 关系型数据库 虚拟化
WIndows Server 远程桌面服务—RDS
WIndows Server 远程桌面服务—RDS
159 1
|
25天前
|
关系型数据库 MySQL 数据库
RDS MySQL灾备服务协同解决方案构建问题之数据库备份数据的云上云下迁移如何解决
RDS MySQL灾备服务协同解决方案构建问题之数据库备份数据的云上云下迁移如何解决
|
1月前
|
关系型数据库 数据库 数据安全/隐私保护
"告别繁琐!Python大神揭秘:如何一键定制阿里云RDS备份策略,让数据安全与效率并肩飞,轻松玩转云端数据库!"
【8月更文挑战第14天】在云计算时代,数据库安全至关重要。阿里云RDS提供自动备份,但标准策略难以适应所有场景。传统手动备份灵活性差、管理成本高且恢复效率低。本文对比手动备份,介绍使用Python自定义阿里云RDS备份策略的方法,实现动态调整备份频率、集中管理和智能决策,提升备份效率与数据安全性。示例代码演示如何创建自动备份任务。通过自动化与智能化备份管理,支持企业数字化转型。
35 2

热门文章

最新文章