mysql 5.7 不支持单条 alter table 语句中多次 rename index,因语法解析器仅允许该子句出现一次;需分多条独立语句执行,且每条须单独提交。

MySQL 5.7 不支持在一个 ALTER TABLE 语句中执行多个索引重命名操作,根本原因是语法解析器只允许每个 RENAME INDEX 子句单独出现,且不支持重复使用该子句。
MySQL 5.7 的 RENAME INDEX 语法只接受单次声明
你不能写成这样:
ALTER TABLE `users` RENAME INDEX `idx_name` TO `idx_user_name`, RENAME INDEX `idx_email` TO `idx_user_email`;
MySQL 会直接报错:ERROR 1064 (42000): You have an error in your SQL syntax。因为 RENAME INDEX 是一个原子性子句,不是可叠加的列表项。官方语法定义里它只能出现一次,后面跟一对旧名/新名。
常见误判是把它类比成 DROP COLUMN 或 ADD COLUMN ——但那些支持逗号分隔多个操作,RENAME INDEX 不行。
为什么不能合并成一条 ALTER?和锁表无关,纯属解析限制
有人以为“合并是为了减少锁”或“避免多次 DDL 开销”,其实不是。即使你分两次执行:
ALTER TABLE `users` RENAME INDEX `idx_name` TO `idx_user_name`;ALTER TABLE `users` RENAME INDEX `idx_email` TO `idx_user_email`;
这两条在 MySQL 5.7 中都是在线、不锁表、不重建索引的轻量操作。性能上几乎无差别,瓶颈不在执行次数,而在语句本身不被语法允许。
真正卡住的是 parser:它看到第一个 RENAME INDEX 后,就期望语句结束或进入下一个独立的 ALTER TABLE 块,而不是继续解析另一个 RENAME INDEX。
批量改索引名的正确姿势:生成并顺序执行多条独立语句
别手写,用 information_schema.statistics 自动生成:
SELECT CONCAT('ALTER TABLE `', table_name, '` RENAME INDEX `', index_name, '` TO `',
table_name, '_idx_', GROUP_CONCAT(column_name ORDER BY seq_in_index SEPARATOR '_'), '`;')
FROM information_schema.statistics
WHERE table_schema = 'your_db'
AND index_name NOT IN ('PRIMARY')
GROUP BY table_name, index_name;
执行结果是一堆独立的 ALTER TABLE ... RENAME INDEX ...,复制粘贴或脚本循环执行即可。
注意点:
- 必须确保每条语句单独执行(不能用分号连写进一个 client 请求,某些客户端会截断)
- 如果涉及主从,建议在低峰期逐条跑,避免从库 SQL 线程积压
- 不要依赖执行顺序做依赖关系(比如先改 A 再改 B),因为它们之间无耦合
最易被忽略的是:哪怕你只改一个索引名,也得确认目标名没被其他索引占用——RENAME INDEX 不校验冲突,直到执行时才报 ERROR 1022 (23000): Can't write; duplicate key in table,而这时已经晚了。











