MySQL表级COLLATION无法覆盖显式声明的列级COLLATION,需用ALTER TABLE MODIFY逐列修改并重写约束索引;GUI工具易静默失败,应先确认字符集再改COLLATION;大表修改须评估锁与性能,函数索引可能失效需重建。
MySQL 表多列批量改 COLLATION 为什么不能只改表级?
因为列级 collation 优先级高于表级,即使你用 alter table ... convert to character set utf8mb4 collate utf8mb4_unicode_ci,已有列的显式声明(比如建表时写了 varchar(255) collate utf8mb4_general_ci)会保留,不会被“覆盖”。结果就是新列生效、老列照旧——看着改了,实际没动。
实操建议:
- 先查清哪些列是“顽固派”:
SELECT column_name, collation_name FROM information_schema.columns WHERE table_schema = 'your_db' AND table_name = 'your_table' AND collation_name != 'utf8mb4_unicode_ci';
- 生成批量
ALTER TABLE ... MODIFY语句,而不是CONVERT TO - 注意:
MODIFY会重建列,如果该列有默认值、约束或索引,需一并重写,否则丢失
用 INFORMATION_SCHEMA 自动生成修改语句最稳
手动写几十条 ALTER TABLE 容易漏、易手抖。直接查元数据拼 SQL 是唯一靠谱做法,尤其面对视图、分区表或含生成列的表时,人工判断类型和长度极易出错。
实操建议:
- 执行这个查询(替换
your_db和your_table):SELECT CONCAT('ALTER TABLE `', table_name, '` MODIFY `', column_name, '` ', column_type, ' COLLATE utf8mb4_unicode_ci', IF(is_nullable = 'YES', ' NULL', ' NOT NULL'), ';') AS ddl FROM information_schema.columns WHERE table_schema = 'your_db' AND table_name = 'your_table' AND collation_name IS NOT NULL AND collation_name != 'utf8mb4_unicode_ci'; - 结果复制出来,逐条执行;别一次性全塞进客户端——万一某列是
TEXT且有全文索引,MODIFY会报错 - 如果列类型含
CHARACTER SET显式声明(如VARCHAR(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci),column_type里不带字符集,得额外补上CHARACTER SET utf8mb4
图形界面工具(如 DBeaver / Navicat)点几下就改?小心静默失败
很多 GUI 工具“编辑列”时只允许改 Collation 下拉框,但底层可能发的是 CHANGE COLUMN,而没带 CHARACTER SET。结果 MySQL 按当前列的字符集推导新 COLLATION,若原字符集是 latin1,选 utf8mb4_unicode_ci 会被自动忽略——它根本不兼容。
常见错误现象:
- 点保存后无报错,刷新看
collation_name还是老样子 - 工具日志里出现警告:
Ignoring invalid character set utf8mb4 for column xxx - 改完发现中文存成问号,说明字符集没同步切过去
实操建议:
- 在 GUI 里改之前,先用
SHOW CREATE TABLE your_table确认该列当前字符集 - 如果字符集不是
utf8mb4,必须先改字符集,再改COLLATION,两步不能合并 - DBeaver 中勾选 “Show full column definition” 才能看到真实 DDL,避免被简化界面误导
ALTER TABLE ... CONVERT TO 和 MODIFY 的性能与锁表现差异
对大表来说,这不是语法洁癖问题,而是停机时间问题。CONVERT TO 会重写整张表(包括所有行),而 MODIFY 只重写目标列——但 MySQL 8.0.12+ 对支持 ALGORITHM=INSTANT 的列类型(如 VARCHAR 长度不变、仅改 COLLATION)才真正不锁表。
实操建议:
- 确认 MySQL 版本:
SELECT VERSION();,低于 8.0.12 别信“instant”宣传 - 对
TEXT或带全文索引的列,MODIFY必触发表重建,提前评估耗时 - 生产环境务必加
LOCK=NONE测试是否被拒绝,被拒就说明不支持 instant,得走低峰期 + 备份方案
最容易被忽略的一点:改完一列后,如果该列上有函数索引(比如 INDEX idx_name ((UPPER(name)))),COLLATION 切换可能导致索引失效,查询计划突变——得连索引一起重建。










