SQL 索引维护与碎片整理方法

13次阅读

碎片率低于 30% 用 reorganize(在线、低开销但不更新统计信息),高于 30% 用 rebuild(彻底重排页、更新统计信息但锁表或耗资源);mysql 用 algorithm=inplace 的 alter table 在线重建;postgresql 推荐 pg_repack 避免锁表。

SQL 索引维护与碎片整理方法

SQL Server 重建索引时 REBUILDREORGANIZE 怎么选

看碎片率决定用哪个:低于 30% 用 REORGANIZE,高于 30% 用 REBUILD。前者在线、低开销但效果有限;后者锁表(除非加 ONLINE = ON)、耗资源但能彻底重排页和更新统计信息。

常见错误是不管碎片率全用 REBUILD——小表或低碎片索引重建反而引发日志暴涨、阻塞应用;反过来,对 70% 碎片的索引只 REORGANIZE,基本白干,查询性能几乎没改善。

  • REORGANIZE 不需要额外磁盘空间,适合空间紧张环境
  • REBUILD 会重置 stats_date(),触发后续查询计划重编译;REORGANIZE 不更新统计信息,得手动跑 UPDATE STATISTICS
  • SQL Server Standard 版不支持 ONLINE = ON,重建大索引必须停业务窗口

MySQL InnoDB 表怎么安全清理索引碎片

InnoDB 没有显式“重建索引”命令,本质靠 ALTER TABLE …… ENGINE=InnoDBOPTIMIZE TABLE 触发重建。但这两者行为不同:OPTIMIZE TABLE 在 MySQL 5.6+ 实际就是 ALTER TABLE …… FORCE,会锁表;而 ALGORITHM=INPLACEALTER TABLE 才真正在线。

容易踩的坑是直接在生产库跑 OPTIMIZE TABLE——尤其大表,可能持续锁表数小时。更糟的是,如果开启了 innodb_file_per_table=OFFOPTIMIZE 还会把数据挪进系统表空间,彻底无法收缩。

  • 确认 innodb_file_per_table=ON(查 SHOW VARIABLES LIKE 'innodb_file_per_table'
  • 优先用 ALTER TABLE t1 ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE(5.6+ 支持)
  • 避免在从库执行,因为 OPTIMIZE 是 DDL,在基于语句复制(SBR)下可能造成主从延迟或不一致

PostgreSQL 中 VACUUM FULLCLUSTER 的真实代价

VACUUM FULL 不只是清理死元组,它会重写整个表并重建所有索引——等价于锁表 + 全量拷贝 + 索引重建。而 CLUSTER 更狠:按指定索引物理重排表数据,之后所有顺序扫描都更快,但原索引会失效,必须重建。

很多人以为 VACUUM FULL 是“深度清理”,结果发现执行完磁盘没释放——因为没配 vacuum_cleanup_index_scale_factor 或表上有长事务阻塞了清理。更隐蔽的问题是:CLUSTER 后索引的 pg_class.relpages 可能变大,因填充因子(fillfactor)被重置为默认 100,下次更新反而更快产生碎片。

  • VACUUM FULL 期间表不可读写,且无法被 CANCEL,只能等或杀进程
  • CLUSTER 必须先有索引,且该索引不能是表达式索引或部分索引
  • 想省事?用 pg_repack 工具——它模拟在线 CLUSTER,但不锁表,代价是多占一倍磁盘空间

索引碎片检测不准的三个典型原因

查出来的碎片率不准,往往不是脚本写错,而是底层统计滞后或视图语义误解。比如 SQL Server 的 sys.dm_db_index_physical_stats 默认用 DETAILED 模式扫全表,但生产库常设成 SAMPLED(快但误差大);PostgreSQL 的 pg_stat_all_indexes.idx_scan 统计的是逻辑扫描次数,和物理碎片无关。

最常被忽略的是:索引碎片本身不等于查询慢。一张只有几百行的表,碎片率 90% 也没影响;而一张高频更新的宽表,即使碎片率 15%,也可能因页分裂导致大量随机 IO。

  • SQL Server:用 mode = 'DETAILED' 查关键索引,但别在高峰期跑
  • MySQL:information_schema.INNODB_SYS_INDEXESsize 字段是页数,不是碎片率,别误当指标
  • PostgreSQL:pg_total_relation_size('tbl') 包含 TOAST 表,单纯看这个值下降≠碎片整理成功

碎片整理不是定期执行的保健操作,而是针对明确性能退化现象的靶向干预。真正难的从来不是命令怎么敲,而是判断“此刻是不是真该动索引”。

text=ZqhQzanResources