LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

SQL Server 越跑越慢?不是 SQL 写错!索引碎片 + 冗余索引才是隐形元凶(实测 25s→3s)

admin
2026年9月9日 11:7 本文热度 140

在前面

前面四篇连载,我们彻底打通了 SQL Server 性能调优的核心闭环: 从统计信息校准、执行计划解读、参数嗅探解决,再到根治 SQL 劣质写法,基本解决了绝大多数显性慢查询问题。

但很多朋友会发现一个诡异的问题: 同样的 SQL、同样的索引、同样的写法,刚优化完飞快,跑一段时间性能又慢慢变差。 没有新增业务、没有数据暴涨、没有语句变更,性能却持续退化。

这就是绝大多数运维忽略的数据库隐形慢性病:索引碎片堆积 + 无用索引冗余堆积

索引从不是建好就永久生效,它是需要定期养护的基础设施。 今天这篇收尾运维篇,全部是生产可落地的实操,教你如何科学维护索引、清理垃圾索引,守住数据库长期稳定。

如果你是新读者,本文可直接作为索引运维独立实操指南,无需阅读前文即可上手。

一、先搞懂:索引碎片到底是什么?

我们常用的非聚集索引、聚集索引,本质都是 B + 树结构。

ERP 系统高频的新增、修改、删除、归档操作,会持续改动索引页数据: 页面数据被删除、数据移位、页面拆分、空间空置…… 

久而久之就会出现:逻辑顺序混乱、物理磁盘顺序错乱、大量空页闲置,这就是索引碎片。

直白人话:

无碎片索引:数据连续规整,查询一次读取就能拿到连续数据,IO极低;

高碎片索引:数据东一块西一块,查询需要读取更多磁盘页,逻辑读、物理读翻倍,查询持续变慢。

二、碎片不清理,会引发哪些生产故障?

很多人觉得碎片不影响使用,只是轻微损耗,这是严重误区。 在 ERP 千万级大表(MRTLOT、RESVT 等)上,高碎片会引发连锁问题:

  1. 查询性能持续退化:索引有序性变差,Seek 效率下降,极易从精准查找变为扫描;
  2. 写入压力暴涨:新增、修改单据需要频繁维护碎片化索引,CPU、IO 持续偏高;
  3. 统计信息更新失真:碎片过高会干扰数据分布统计,间接诱发参数嗅探、执行计划错乱;
  4. 数据库空间浪费:大量索引空页堆积,占用磁盘空间却无任何业务价值。

核心真相:小表碎片无伤大雅,大表碎片是性能雪崩的源头。

三、实战脚本:一键查询全表索引碎片率(SQL2014兼容)

直接使用以下脚本,排查目标表所有索引碎片情况,精准定位需要维护的索引,并生成维护 SQL 脚本。

SELECT    OBJECT_NAME(ips.object_id) AS TableName,    i.name AS IndexName,    i.type_desc,    ips.avg_fragmentation_in_percent,    ips.page_count,    CAST(ips.page_count * 8.0 / 1024 AS DECIMAL(18,2)) AS SizeMB,    CASE        WHEN i.type_desc='HEAP' THEN 'ALTER TABLE [dbo].['+OBJECT_NAME(ips.object_id)+'] REBUILD;'WHEN ips.avg_fragmentation_in_percent > 30 THEN 'ALTER INDEX [' + i.name + '] ON [' + OBJECT_NAME(ips.object_id) + '] REBUILD WITH (SORT_IN_TEMPDB=ON,MAXDOP=4,FILLFACTOR=80);'        WHEN ips.avg_fragmentation_in_percent BETWEEN 10 AND 30 THEN 'ALTER INDEX [' + i.name + '] ON [' + OBJECT_NAME(ips.object_id) + '] REORGANIZE;'        ELSE '-- OK'    END AS ActionSQLFROM sys.dm_db_index_physical_stats(DB_ID(), NULLNULLNULL'LIMITED') ipsJOIN sys.indexes i ON ips.object_id=i.object_id AND ips.index_id=i.index_idWHERE ips.avg_fragmentation_in_percent > 10       AND ips.page_count > 1000      AND OBJECT_NAME(ips.object_id) NOT LIKE 'sys%'ORDER BY ips.avg_fragmentation_in_percent DESC;
官方实战判定标准(直接照搬运维规范)
✅ 碎片率 0%-5%:无需处理,正常波动,不用干预; 
✅ 碎片率 5%-30%:索引重组(REORGANIZE),轻量整理,在线执行、无锁、不影响业务; 
✅ 碎片率 >30%:索引重建(REBUILD),重度碎片,需要重构索引结构。

四、两种索引维护方式,90%人都用错了

索引维护只有两种方式:重组、重建。很多人不管碎片高低,统一重建,白白增加业务压力。

1、索引重组 REORGANIZE(轻量日常维护)

适用场景:碎片 5%-30%、日常巡检维护、业务不中断 

特点:在线整理、渐进式优化、几乎无锁、不影响读写业务、压力极小。

--碎片 5%~30% → REORGANIZE(重组,不锁表)--单索引重组 实例 ALTER INDEX I_ALLSTOCK_CO_CODE_TDATE ON ALLSTOCK REORGANIZE;

2、索引重建 REBUILD(深度根治重度碎片)

适用场景:碎片 > 30%、长期未维护、数据大批量归档 / 删除后 

特点:彻底删除旧索引、重新生成全新规整索引,碎片直接清零,性能最优

⚠️ 关键兼容提醒:SQL2014标准版不支持在线重建,高峰期会锁表,务必选择凌晨低峰窗口执行!

--高碎片30% 索引重建ALTER INDEX PK_ALLSTOCK ON ALLSTOCK REBUILD WITH(SORT_IN_TEMPDB=ON,MAXDOP=4,FILLFACTOR=80);

大表补充建议:对于 >50GB 的超大表,即使碎片 >30%,也建议优先使用 REORGANIZE 分批次整理,或使用分区级重建,避免单次维护窗口不够导致任务超时。

运维铁律:小碎片重组、大碎片重建,绝不盲目全量重建。

五、比碎片更坑的隐患:无用冗余索引

很多数据库越优化越卡,不是索引太少,是索引太多、太乱、大量冗余。 

新手只知道建索引,从不删索引,长期下来一张大表十几条索引: 

相似索引、重复索引、长期零访问索引、被覆盖废弃索引堆积。

冗余索引的致命危害

  1. 查询几乎无收益,极少被优化器选用;
  2. 写入开销翻倍:新增、修改、删除单据,需要同步维护所有冗余索引,严重拖慢事务速度;
  3. 加剧碎片产生、占用磁盘空间、拖累整体性能。

实战脚本:查询表从未使用的索引

-- sql --单表未使用索引查询SELECT    OBJECT_NAME(s.object_id) AS 表名,    i.name AS 索引名FROM sys.dm_db_index_usage_stats sRIGHT JOIN sys.indexes i ON s.object_id = i.object_id AND s.index_id = i.index_idWHERE OBJECT_NAME(s.object_id) = '表名' AND s.user_seeks IS NULL;
判定标准与安全警告:
上线超过1个月,且期间数据库实例未发生过重启,零Seek、零扫描的索引,可判定为僵尸索引。

重要修正说明
sys.dm_db_index_usage_stats 会在 SQL Server 实例重启数据库分离/附加后清零
REBUILD 不会清零,索引重建后使用统计会被保留
- 因此判断僵尸索引时,务必确认数据库已稳定运行超过一个月且未重启,切勿在刚重启的库里直接删索引!

六、高危误区:相似重复索引,绝大多数人都在踩

这是最隐蔽的索引冗余:前缀相同的复合索引

举例:

索引A:APPROVED,TDATE

索引B:APPROVED,TDATE,JOBNO

结论:索引A完全冗余,可以直接删除。

符合最左前缀原则,长索引可以完全替代短索引,保留长索引、删除短索引,零性能损耗,大幅减负写入压力。

删除前必须确认的安全检查清单

1、是否 UNIQUE 约束 | 短索引如果是唯一约束,长索引不是唯一,不能删除 
2、是否聚集索引 | 聚集索引决定了数据物理存储顺序,不能随便删除 
3、是否被外键引用 | 外键引用的索引删除可能报错,需先处理外键 
4、是否包含特殊 INCLUDE 列 | 长索引不一定覆盖了短索引的 INCLUDE 列,需逐一比对 

建议删除前务必在测试环境验证,确认业务查询的执行计划没有退化,再在生产环境操作。

七、实战运维复盘

本次主要优化百万级以上大表,共排查出以下典型问题:

1、索引碎片高达40%+,长期未维护,查询IO持续偏高;

2、存在99条零访问僵尸索引,长期占用资源、无任何查询收益;

3、存在前缀重复索引,写入冗余开销严重。

落地优化动作:

1、REORGANIZE重组索引1500个左右;

2、REBUILD重建索引1000个左右;

3、删除99条长期无用僵尸索引;

4、清理重复前缀冗余索引,保留最优覆盖索引。

优化结果:最好的就是用户都反馈:速度快了。原来的产品资料保存需要25秒,现在只需要3秒。

单据保存、批量修改速度明显提升,后台报表IO进一步下降,数据库稳态性能大幅优化。

八、可直接落地的索引运维规范(建议收藏)

结合ERP生产经验,整理一套标准化运维节奏,彻底告别索引乱象:

1每日巡检:监控大表索引碎片波动、异常IO波动;

2每周轻维护:对5%-30%碎片索引统一REORGANIZE重组;

3每月深维护:低峰窗口对高碎片索引REBUILD重建;

4每月清理:排查零使用索引、重复索引,及时清理减负;

5大批量数据操作后:归档、批量删除完成后,必须维护索引+更新统计信息。

6、每次维护前后:记录索引大小、碎片率、主要查询执行时间,验证正向提升,防止填充因子调整导致统计信息异常

目前自动化方案

我已创建两个存储过程:

  • REORGANIZE 重组 SP:定时任务每周日晚上 22 点执行
  • REBUILD 重建 SP:定时任务每月 1 号凌晨 2 点执行

每次执行均记录:操作表名、索引名、操作前碎片率、执行时间、页。

写在最后

很多人调优只关注「怎么建索引」,却忽略了「怎么养索引、怎么清索引」。 优秀的索引结构,离不开长期科学的运维;干净的索引环境,才是数据库稳定的基石。

碎片堆积、冗余索引泛滥,看似无伤大雅,实则会慢慢蚕食数据库性能,最终引发批量卡顿、业务超时。

到这里,索引全套调优体系(统计信息、执行计划、参数嗅探、SQL 写法、索引运维)已经全部讲完。


阅读原文:点击这里


该文章在 2026/9/9 11:07:40 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-1  粤公网安备44030602007207号