alter table ... modify column 或 change column 是修改单个字段字符集的正确写法,需显式指定完整字段定义、字符集及排序规则,如:alter table users modify column name varchar(100) character set utf8mb4 collate utf8mb4_unicode_ci;convert to character set 会批量修改整表且隐式转换数据,易致乱码。

ALTER TABLE 修改单个字段字符集的正确写法
直接用 ALTER TABLE ... MODIFY COLUMN 或 ALTER TABLE ... CHANGE COLUMN 才能真正更新字段的字符集,ALTER TABLE ... CONVERT TO CHARACTER SET 会改整张表,且对已有数据做隐式转换,容易出乱码。
常见错误是只写 ALTER TABLE t1 CHARACTER SET = utf8mb4 —— 这只改表默认字符集,不改已有字段定义。
实操建议:
- 用
MODIFY COLUMN保持字段名、类型、约束不变,只更新字符集和排序规则 - 必须显式写出完整字段定义,比如
VARCHAR(255)不能省略 - 排序规则建议同步指定,例如
utf8mb4_unicode_ci,避免依赖数据库默认值
示例:
ALTER TABLE users MODIFY COLUMN name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
批量生成 ALTER TABLE 语句的实用 SQL
手动写几十条 ALTER TABLE 太容易漏或错,直接从 information_schema.COLUMNS 查出目标字段,拼出可执行语句更可靠。
注意点:
- 只选
CHAR、VARCHAR、TEXT类型字段,数值/时间类型不需要改 - 过滤掉已为
utf8mb4的字段,避免重复执行报错 - 排序规则要和目标字符集匹配,
utf8mb4_general_ci已废弃,优先用utf8mb4_unicode_ci或utf8mb4_0900_as_cs(MySQL 8.0+)
示例(生成所有非 utf8mb4 的 VARCHAR 字段修改语句):
SELECT CONCAT('ALTER TABLE `', table_schema, '`.`', table_name, '` MODIFY COLUMN `', column_name, '` ', column_type, ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;')
FROM information_schema.COLUMNS
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
AND character_set_name IS NOT NULL
AND character_set_name != 'utf8mb4'
AND data_type IN ('char', 'varchar', 'text', 'tinytext', 'mediumtext', 'longtext');
执行前必须检查的三个关键项
跳过这三步,轻则语句报错中断,重则数据乱码不可逆:
- 检查字段是否被索引引用:
SHOW CREATE TABLE table_name看是否有前缀索引(如VARCHAR(255)建了INDEX(col(191))),改完字符集后,utf8mb4单字符最多占 4 字节,原来utf8下 191 字符的索引长度可能超限制,需同步调整前缀长度 - 确认表存储引擎:MyISAM 对大字段索引限制更严,InnoDB 更宽松但仍有页大小限制(如
ROW_FORMAT=DYNAMIC才支持长文本字段) - 验证当前连接字符集:
SHOW VARIABLES LIKE 'character_set%',确保客户端、连接、结果集都是utf8mb4,否则SELECT出来的中文可能显示为问号,误判转换失败
ALTER TABLE 在线执行的风险与规避方式
MySQL 5.6+ 支持部分 ALTER TABLE 的 online DDL,但 MODIFY COLUMN 改字符集仍大概率触发表重建(尤其有全文索引或外键时),会导致锁表。
影响判断依据:
- 表大小决定执行时长,千万级数据可能卡住几分钟甚至更久
- 若业务有写入压力,期间
INSERT/UPDATE会被阻塞,不是“只读”那么简单 -
CONVERT TO CHARACTER SET更危险:它会尝试转换所有字符串列的值,若原数据实际是 latin1 编码却标记为 utf8,转换后直接变乱码
稳妥做法:
- 小表(
- 大表先在从库或测试环境跑通,观察
SHOW PROCESSLIST和磁盘 I/O - 生产环境优先用
pt-online-schema-change(Percona Toolkit),它通过影子表 + 触发器实现无锁变更
字符集转换不是改个配置就能生效的事,字段定义、索引结构、连接层、存储引擎全得对齐,漏掉任意一环,都可能让“看起来改好了”的表,在某次查询或导入时突然吐出一堆问号。











