Sql Server数据库在长期运行过程中,频繁的增删改操作会导致索引页产生碎片,索引碎片率过高会直接降低数据查询的速度,因此定期整理索引是数据库维护的重要工作。合理的索引整理可以合并碎片页,提升索引的存储效率和查询性能。
索引碎片检测
在整理索引之前,需要先检测索引的碎片率,判断是否需要整理。Sql Server提供了sys.dm_db_index_physical_stats动态管理函数,可以查询指定表或索引的物理状态,包括碎片率信息。
以下是查询指定数据库所有索引碎片率的语句示例:
-- 查询当前数据库所有索引的碎片信息
SELECT
OBJECT_NAME(ips.object_id) AS 表名,
i.name AS 索引名称,
ips.index_id AS 索引ID,
ips.avg_fragmentation_in_percent AS 平均碎片率,
ips.page_count AS 页数量
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') AS ips
JOIN sys.indexes AS i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.avg_fragmentation_in_percent > 10 -- 筛选碎片率大于10%的索引
ORDER BY ips.avg_fragmentation_in_percent DESC;
通常碎片率在10%到30%之间时,适合使用ALTER INDEX REORGANIZE语句整理;碎片率超过30%时,建议使用ALTER INDEX REBUILD语句重建索引,重建索引的整理效果更彻底,但会消耗更多系统资源。
单索引整理语句
针对单个索引的整理,可以根据碎片率选择重组或重建操作。
重组索引(碎片率10%-30%)
重组索引是在线的操作,不会阻塞表的正常读写,执行速度较快,适合碎片率较低的场景。
-- 重组指定表的指定索引 ALTER INDEX 索引名称 ON 表名 REORGANIZE; -- 示例:重组用户表的IX_用户_姓名索引 ALTER INDEX IX_用户_姓名 ON 用户表 REORGANIZE;
重建索引(碎片率>30%)
重建索引会重新生成整个索引,清除所有碎片,可指定是否在线执行,离线重建会锁定表,在线重建对业务影响较小。
-- 离线重建索引(会锁定表,适合业务低峰期) ALTER INDEX 索引名称 ON 表名 REBUILD; -- 在线重建索引(Sql Server企业版支持,标准版不支持) ALTER INDEX 索引名称 ON 表名 REBUILD WITH (ONLINE = ON); -- 示例:在线重建订单表的PK_订单主键索引 ALTER INDEX PK_订单 ON 订单表 REBUILD WITH (ONLINE = ON);
批量自动整理索引语句
手动逐个整理索引效率很低,可以编写批量语句,自动检测碎片率并执行对应的整理操作。以下是通用的批量整理脚本:
-- 批量整理当前数据库所有碎片率超标的索引
DECLARE @表名 NVARCHAR(128),
@索引名 NVARCHAR(128),
@碎片率 FLOAT,
@sql NVARCHAR(MAX);
-- 创建临时表存储需要整理的索引信息
CREATE TABLE #索引碎片表(
表名 NVARCHAR(128),
索引名 NVARCHAR(128),
碎片率 FLOAT
);
-- 插入碎片率大于10%的索引信息
INSERT INTO #索引碎片表(表名, 索引名, 碎片率)
SELECT
OBJECT_NAME(ips.object_id),
i.name,
ips.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') AS ips
JOIN sys.indexes AS i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.avg_fragmentation_in_percent > 10
AND i.name IS NOT NULL; -- 排除堆表(没有索引的表)
-- 遍历临时表,执行整理操作
DECLARE 索引游标 CURSOR FOR
SELECT 表名, 索引名, 碎片率 FROM #索引碎片表;
OPEN 索引游标;
FETCH NEXT FROM 索引游标 INTO @表名, @索引名, @碎片率;
WHILE @@FETCH_STATUS = 0
BEGIN
IF @碎片率 >= 30
BEGIN
-- 碎片率超过30%,重建索引(可根据版本决定是否加ONLINE参数)
SET @sql = 'ALTER INDEX ' + @索引名 + ' ON ' + @表名 + ' REBUILD;';
END
ELSE
BEGIN
-- 碎片率10%-30%,重组索引
SET @sql = 'ALTER INDEX ' + @索引名 + ' ON ' + @表名 + ' REORGANIZE;';
END
-- 执行动态SQL
EXEC sp_executesql @sql;
FETCH NEXT FROM 索引游标 INTO @表名, @索引名, @碎片率;
END
CLOSE 索引游标;
DEALLOCATE 索引游标;
-- 删除临时表
DROP TABLE #索引碎片表;
设置自动整理索引作业
要实现索引的自动整理,可以通过SQL Server代理创建定时作业,让系统定期执行上面的批量整理脚本。
创建作业步骤
- 打开SQL Server Management Studio,连接到数据库实例,展开SQL Server代理节点。
- 右键点击作业文件夹,选择新建作业。
- 在常规页面填写作业名称,比如索引自动整理作业。
- 切换到步骤页面,点击新建,步骤名称填写执行索引整理,类型选择Transact-SQL脚本,数据库选择需要整理的数据库,命令框中粘贴上面的批量整理索引语句。
- 切换到计划页面,点击新建,设置作业执行的时间,比如每周日凌晨2点执行,避开业务高峰期。
- 根据需要设置警报和通知,完成作业创建。
作业创建完成后,SQL Server代理会在设定的时间自动执行索引整理脚本,无需手动干预,保障数据库索引始终处于较好的状态。
注意事项
- 重建索引会消耗较多的CPU和IO资源,建议在业务低峰期执行,避免影响正常业务。
- Sql Server标准版不支持在线重建索引,执行REBUILD语句时表会被锁定,需要提前做好业务通知。
- 整理索引前建议备份数据库,避免操作过程中出现意外导致数据问题。
- 对于特别大的表,索引整理耗时可能较长,可以适当调整碎片率的阈值,减少不必要的整理操作。
Sql_Server数据库索引索引整理自动整理修改时间:2026-07-02 10:15:42