RDS SQL Server - 最佳实践 - 高CPU使用率系列之二索引碎片

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: # 摘要 上一篇文章分析了高CPU使用率的原因之一是索引缺失,接下来本系列文章之二的“索引碎片”是CPU高使用率的又一常见的原因。解决索引碎片问题是解决SQL Server服务响应缓慢,查询超时的又一利器。 # 问题引入 “鸟哥,我上一篇文章分享了因为索引缺失导致CPU高使用率的话题,反响不错。接下来,我打算分享索引碎片导致CPU高使用率的话题。”,菜鸟主动找到老鸟汇报工作。 上一篇文章详

摘要

上一篇文章分析了高CPU使用率的原因之一是索引缺失,接下来本系列文章之二的“索引碎片”是CPU高使用率的又一常见的原因。解决索引碎片问题是解决SQL Server服务响应缓慢,查询超时的又一利器。

问题引入

“鸟哥,我上一篇文章分享了因为索引缺失导致CPU高使用率的话题,反响不错。接下来,我打算分享索引碎片导致CPU高使用率的话题。”,菜鸟主动找到老鸟汇报工作。
上一篇文章详情参见链接:RDS SQL Server - 最佳实践 - 高CPU使用率系列之索引缺失

索引碎片是什么

索引碎片既指索引文件页中的空白空间;又指被Page Split的索引页;还指索引失序的数据页。前面两种我们称之为索引内部碎片,后面一种我们叫着索引外部碎片。
前面是干瘪瘪的理论描述,下面举一个关于电话簿实例就比较好理解了:假如电话簿按照城市名称、姓名和电话号码组合排序的方式来存储所有人员的联系电话。以下几种情况都需要更新电话簿:
 当一个人更换电话号码的时候或者改名字的时候(西方国家女子结婚后,会修改姓氏为老公的姓,比如:奥巴马的老婆叫米歇尔-奥巴马):需要更新操作
 当一个人从一个城市搬迁到另一个城市的时候:需要删除原来的记录,在相应的城市插入新记录
 当有新人办理了电话业务的时候:需要在相应城市插入记录
 当作废电话号码的时候:需要删除对应条目
这些操作带来的后果是:更新操作可能导致失序(out of order);删除操作导致空白条目(empty space);插入操作导致分页(page split)。结果就是最终形成电话簿(类似于索引)的碎片外部碎片和内部碎片。

索引碎片的危害

清楚了索引是什么的问题,我们来看看索引碎片的危害。
假如,一本完整存放(没有任何碎片)的电话簿刚好1000页,而由于前面讲的种种操作,导致了10%的碎片,那么最终我们需要1100页来存放。我们每一本书将浪费100页的纸张来印刷,也将浪费掉每个人10%的查询和阅读时间。放在SQL Server索引碎片的角度,原理是相通的:由于SQL Server读取数据的最小单位是数据页,而不是单条记录,所以,相同的查询语句需要SQL Server读取更多的磁盘宽度,加之索引碎片会浪费更多的内存资源来存放读取到的数据。因此,碎片化程度越高意味着更高的内存使用浪费和更低的查询性能。微软建议索引碎片率在5%到30%之间,做索引重组;碎片率超过30%,做索引重建工作。
详情参考链接:Reorganize and Rebuild Indexes

解决方法

我们从以下几个方面来描述解决方法:
 模拟产生索引碎片
 获取索引碎片信息
 重建索引
 前后对比

模拟产生索引碎片

我假设需要变更100万条数据记录,这些变更包括UPDATE、DELETE和INSERT操作。在前一篇文章创建的表dbo.SalesOrder基础上,我们使用如下方法变更数据:

USE TestDb
GO

SET NOCOUNT ON

DECLARE
    @do INT = 0
    , @loop INT = 1000000
    , @sql NVARCHAR(MAX) = N''
;

WHILE @do < @loop
BEGIN
        SET @sql = 
        CASE  
            WHEN @do % 3 = 0
                THEN N'DELETE TOP(1) FROM dbo.SalesOrder;'
            WHEN @do % 3 = 1
                THEN N'UPDATE TOP(1) A SET OrderQty = OrderQty + 1, Price = Price - 1, OrderDate = GETDATE() FROM dbo.SalesOrder AS A'
            WHEN @do % 3 = 2
                THEN N'INSERT INTO dbo.SalesOrder(OrderID, ItemID, UserID, OrderQty, Price, OrderDate, LastUpdateTime, OrderComment)
                            SELECT TOP 1 NEWID(),ItemID, UserID, OrderQty, Price, OrderDate, LastUpdateTime, OrderComment
                            FROM dbo.SalesOrder
                '
            ELSE N''
        END

        EXEC sys.sp_executesql @sql

        IF @do % 2000 = 0
        BEGIN
            RAISERROR('%d rows', 10, 1, @do) WITH NOWAIT
        END

        SET @do = @do + 1;
END
GO

获取索引碎片信息

我们可以使用系统函数sys.dm_db_index_physical_stats来获取索引碎片信息。查询索引碎片的方法如下:

USE TestDb
GO

SELECT 
        db_name(database_id) AS db_name
        ,object_name(ix.object_id) AS object_name
        ,ix.name
        ,avg_fragmentation_in_percent
        ,*
FROM sys.dm_db_index_physical_stats(db_id(),object_id('dbo.SalesOrder','U'),NULL,NULL,'LIMITED') AS fra
    CROSS APPLY sys.indexes AS ix WITH (NOLOCK) 
WHERE ix.object_id = fra.object_id
    and ix.index_id = fra.index_id

EXEC sys.sp_spaceused SalesOrder

查询结果展示如下图所示:
01.png

重建索引

找准了解决问题的方向,处理起来就变得轻车熟路了,从查询结果我发现主键碎片率达到了92.2%,已经是非常之高了。重建索引的方法:

USE TestDb
GO

ALTER INDEX ALL
ON dbo.SalesOrder REBUILD
WITH (ONLINE = ON, FILLFACTOR = 90)
;

再次执行索引碎片查询,结果如下:
02.png

前后对比

重整索引碎片以后,主键碎片率从92.2%降低到0.1%;索引空间、数据空间和总空间大小分别减少了4.3%、52.8%和72.4%,平均空间减少达43.17%。
03.png

注意事项

在产品环境中重建索引需要十分小心,原因是:
 重建索引会消耗大量的系统I/O读写资源。
 重建索引会导致查询进程的死锁或者锁等待,尤其是非企业版SQL Server(企业版可以使用ONLINE选项来最大限度规避这个问题)。
 重建索引会导致数据库日志文件暴涨,而因此会给Database Mirroring、Log Shipping和Backup带来压力。
所以,请选择业务低谷期进行索引碎片重整的操作。

总结

这篇文章从索引碎片是什么,有哪些危害,如何解决碎片问题和需要注意的事项等方面,详细探讨了导致高CPU使用率的又一常见原因--索引碎片。

引用

Stop Worrying About SQL Server Fragmentation
Reorganize and Rebuild Indexes

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
4月前
|
SQL 关系型数据库 MySQL
MySQL Server 层四个日志
MySQL Server 层四个日志
68 0
MySQL Server 层四个日志
|
1月前
|
SQL 关系型数据库 MySQL
IDEA+Mysql+Sqlserver安装步骤_kaic
IDEA+Mysql+Sqlserver安装步骤_kaic
|
4月前
|
SQL 关系型数据库 MySQL
使用Flink CDC从SQL Server同步数据到MySQL
使用Flink CDC从SQL Server同步数据到MySQL
149 1
|
6天前
|
关系型数据库 MySQL Linux
Linux联网安装MySQL Server
Linux联网安装MySQL Server
20 0
|
2月前
|
关系型数据库 MySQL 数据库
Host 'XXX' is not allowed to connect to this MySQL server 解决方案
Host 'XXX' is not allowed to connect to this MySQL server 解决方案
|
2月前
|
SQL 关系型数据库 MySQL
mysql和sql server
mysql和sql server
32 1
|
3月前
|
关系型数据库 MySQL
mysql及sqlserver修改字段名和字段长度
mysql及sqlserver修改字段名和字段长度
31 0
|
3月前
|
关系型数据库 MySQL 数据库
Client does not support authentication protocol requested by server; consider upgrading MySQL client
Client does not support authentication protocol requested by server; consider upgrading MySQL client
|
4月前
|
关系型数据库 MySQL 数据库
远程连接mysql报错:1130 - Host XXX is not allowed to connect to this MySQL server
远程连接mysql报错:1130 - Host XXX is not allowed to connect to this MySQL server
83 0
|
4月前
|
关系型数据库 MySQL 数据安全/隐私保护
(解决)Can‘t connect to MySQL server on ‘localhost3306‘ (10061)
(解决)Can‘t connect to MySQL server on ‘localhost3306‘ (10061)
39 0