MyISAM不支持Online DDL,所有DDL强制COPY并全程加排他锁;迁移至InnoDB是唯一可靠解法,需满足innodb_file_per_table=ON、充足磁盘空间,并用EXPLAIN验证索引命中。

MyISAM根本不支持Online DDL,别试ALGORITHM=INPLACE
MySQL对MyISAM引擎的任何DDL操作(如ADD COLUMN、ADD INDEX、MODIFY COLUMN)都强制走COPY算法,必然全程加排他锁——无论你是否显式写ALGORITHM=INPLACE,MySQL会直接报错:ALGORITHM=INPLACE is not supported for this operation on a table with engine MYISAM。这不是配置问题,是引擎能力缺失。
常见错误现象包括:
- 执行
ALTER TABLE t1 ADD INDEX idx_name (name)后,所有对该表的INSERT/UPDATE/DELETE全部阻塞,SHOW PROCESSLIST中大量线程状态为Waiting for table metadata lock - 即使只加一个二级索引,大表操作也可能持续数小时,期间业务完全不可写
迁移到InnoDB是唯一可靠解法,不是“建议”
把MyISAM表转成InnoDB后,绝大多数DDL(如加索引、加字段)才能真正启用Online DDL。转换命令就是:
ALTER TABLE your_table_name ENGINE=InnoDB;
但要注意几个硬性前提:
-
innodb_file_per_table必须为ON(否则ALGORITHM=INPLACE会失败) - 磁盘剩余空间至少 ≥ 原表大小(转换过程需双份存储)
-
ALTER TABLE本身会加表级元数据锁,务必避开业务高峰执行 - 转换完成后,立刻用
EXPLAIN FORMAT=JSON SELECT * FROM your_table_name WHERE ...验证查询是否命中索引,避免因缺失索引导致后续UPDATE又退化为全表扫描锁表
实在不能迁移?只能用pt-online-schema-change兜底
如果因历史原因无法立刻切换引擎(比如依赖MyISAM全文索引、或应用层硬编码了ENGINE=MYISAM),必须用第三方工具绕过原生限制。推荐pt-online-schema-change,它不依赖MySQL引擎特性,而是通过触发器同步增量数据:
- 执行前确认表有主键或唯一非空索引(否则分片复制会失败)
- 命令示例:
pt-online-schema-change --alter "ADD INDEX idx_status(status)" D=your_db,t=your_table --execute - 注意:触发器会在原表上产生额外开销,高QPS写入场景下可能引发锁争用,建议配合
--max-load参数限流 - 该工具在
RENAME TABLE最后一步仍需短暂持有排他锁(毫秒级),但已远优于原生ALTER的小时级阻塞
为什么不用gh-ost?它对MyISAM无效
gh-ost底层依赖MySQL binlog解析,而MyISAM表**不写binlog**(除非显式开启log_bin_trust_function_creators=1且使用特殊配置,但极不稳定)。尝试运行会直接报错:Cannot find binlog events for table `db`.`table`。所以面对MyISAM,gh-ost从第一步就走不通,不要浪费时间调试。
真正容易被忽略的是:很多团队以为“加了索引就能解决锁表”,却没意识到MyISAM下SELECT虽不锁表,但一旦UPDATE没走索引,照样全表扫描+全表锁——这种锁和DDL无关,但效果一样致命。所以迁移后第一件事,不是加索引,是用EXPLAIN逐条核验所有DML语句的执行计划。











