不能用 group by 统计碎片率,因为 sys.dm_db_index_physical_stats 返回的是每个索引的独立碎片数据,同一表不同索引碎片率差异大,分组会掩盖关键细节;应按碎片区间分类统计并筛选 page_count > 1000、index_id > 0 的有效索引。

直接查 sys.dm_db_index_physical_stats 就行,别用分组统计“检测碎片率”——它本身不产出可分组的碎片指标,强行 GROUP BY 会掩盖关键细节,还可能误判。
为什么不能靠 GROUP BY 统计碎片率?
sys.dm_db_index_physical_stats 返回的是每个索引的独立碎片数据(avg_fragmentation_in_percent),不是按表或数据库聚合的统计值。碎片是索引级现象,同一张表多个索引碎片程度可能天差地别:
- 聚集索引碎片率 5%,非聚集索引却高达 42% GROUP BY 表名后取 AVG 或 MAX,会把这两种情况混为一谈
- 小索引(
page_count )天然波动大,平均后失真 - 碎片处理策略(
REORGANIZEvsREBUILD)依赖单个索引的精确值,不是“表平均值”
真正该查什么字段、怎么过滤?
重点看三个字段组合判断,而不是求和或分组:
-
avg_fragmentation_in_percent:核心指标,>30% 建议REBUILD,5–30% 可REORGANIZE -
page_count:排除噪音,page_count > 1000才有分析价值(小索引碎片无意义) -
index_id:必须大于 0(跳过堆表,堆无索引结构)
典型查询写法:
SELECT OBJECT_NAME(ips.object_id) AS TableName, i.name AS IndexName, ips.index_type_desc AS IndexType, ips.avg_fragmentation_in_percent, ips.page_count, (ips.page_count * 8.0 / 1024) AS SizeMB FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'SAMPLED') ips INNER JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id WHERE ips.avg_fragmentation_in_percent > 5 AND ips.page_count > 1000 AND i.index_id > 0 ORDER BY ips.avg_fragmentation_in_percent DESC;
如果真要“汇总看趋势”,该怎么做?
不是按表分组算平均碎片,而是按碎片区间做计数统计,用于运维报告:
- 碎片 0–5%:健康,忽略
- 碎片 5–30%:标记为需
REORGANIZE,统计个数 - 碎片 >30%:高危,标记为需
REBUILD,单独列出表名+索引名
示例片段(只统计数量):
SELECT
CASE
WHEN avg_fragmentation_in_percent 1000 AND i.index_id > 0
GROUP BY
CASE
WHEN avg_fragmentation_in_percent <p>碎片率永远是个体索引的诊断值,不是聚合统计指标。盯住单个索引的 <code>avg_fragmentation_in_percent</code> 和 <code>page_count</code>,比任何分组都管用。批量处理时,也应逐个索引判断,而非先分组再决策。</p>











