mysql如何重建索引_mysql索引维护实践

来源:这里教程网 时间:2026-02-28 20:52:17 作者:

ALTER TABLE ... ENGINE=InnoDB 会重建所有索引吗?

会,但不是“重建索引”本身,而是通过重建表来间接重建所有索引。MySQL 在执行

ALTER TABLE t ENGINE=InnoDB
(或
ALGORITHM=INPLACE
不支持时的默认行为)时,会创建新表、逐行拷贝数据、重新生成聚簇索引和所有二级索引。这相当于一次全量索引重建,但开销远大于单纯优化索引结构。

适用场景:表存在严重碎片、页分裂率高、或需要变更行格式(如从

COMPACT
切到
DYNAMIC
)。不推荐仅因个别索引性能下降就用此法。

在线 DDL 支持程度取决于 MySQL 版本和操作类型;5.6+ 对多数二级索引操作支持
ALGORITHM=INPLACE
,无需锁表
执行前务必确认磁盘空间充足——临时表可能占用等量空间 若只改索引,优先用
ALTER TABLE t DROP INDEX idx_name, ADD INDEX idx_name (col)
,比换引擎轻量得多

OPTIMIZE TABLE 能真正“整理”索引碎片吗?

在 InnoDB 中,

OPTIMIZE TABLE
实际等价于
ALTER TABLE ... ENGINE=InnoDB
(并带
ANALYZE TABLE
),它确实能回收空闲页、合并相邻页、重排 B+ 树节点,从而降低索引层级、提升范围扫描效率。但它不是“局部修复”,而是全表级重建。

注意:

OPTIMIZE TABLE
在 MySQL 8.0+ 默认启用
ALGORITHM=INPLACE
的前提下,对某些操作仍会退化为
COPY
模式(例如表含全文索引或使用了加密表空间)。

不要在业务高峰期运行;即使支持 INPLACE,也会持有
S
锁较长时间
对小表( 监控索引碎片更可靠的方式是查
information_schema.INNODB_SYS_INDEXES
PAGE_COUNT
DISTINCT_KEY_COUNT
比值,或用
SHOW INDEX FROM t
观察
Cardinality
是否长期偏低

如何安全地重建单个二级索引而不锁表?

MySQL 5.7+ 支持

ALGORITHM=INPLACE, LOCK=NONE
重建单个索引,前提是该索引不涉及主键、不被外键引用、且表引擎为 InnoDB。

典型命令:

ALTER TABLE t DROP INDEX idx_a, ADD INDEX idx_a (col1, col2) ALGORITHM=INPLACE, LOCK=NONE;

必须同时写
DROP
ADD
—— 分两步执行会短暂丢失索引,导致查询走全表扫描
如果提示
ALGORITHM=INPLACE is not supported
,说明当前操作触发了 COPY 模式(比如修改了列顺序或加了
INCLUDE
字段),此时应评估是否真需重建,或改用 pt-online-schema-change
重建过程中,
INFORMATION_SCHEMA.INNODB_TRX
可能显示长事务阻塞 DDL;建议提前 kill 掉非必要长事务

重建索引后为什么查询没变快?

常见原因不是索引没重建成功,而是统计信息未更新或执行计划未刷新。InnoDB 的索引基数(

Cardinality
)由采样估算得出,重建后不一定自动重采样;而优化器依赖这些统计值选择是否走索引。

强制更新统计信息:
ANALYZE TABLE t;
(轻量,推荐每次重建后执行)
检查实际执行计划:
EXPLAIN FORMAT=JSON SELECT ...
,确认
used_key_parts
rows_examined_per_scan
是否符合预期
留意隐式类型转换:哪怕索引重建了,
WHERE status = '1'
(status 是 INT)仍会导致索引失效 —— 这类问题不会因重建索引而修复
如果用了 Query Cache(已弃用)或客户端缓存了预编译语句,也可能看到“旧计划”,需清空或重启连接 重建索引这件事,表面是操作,底层是数据分布、采样逻辑、优化器决策三者的耦合。最容易被忽略的,其实是
ANALYZE TABLE
的时机和
EXPLAIN
验证动作——没有这两步,重建很可能白忙一场。

相关推荐