迁移数据库或升级 MySQL 后,搜索、保存客户或运行自定义报表突然报 Illegal mix of collations for operation '='。错误说明参与比较的字符串使用了不兼容或不同优先级的 collation。把 SQL 临时加上 COLLATE 可以让一次查询通过,却可能让索引失效,也没有修复后续写入。

从错误 SQL 找到具体两列

保存完整异常与 SQL,定位等号、JOIN、UNION、CASE 或排序中的字符串表达式。随后查看这些列的字符集与 collation:

SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE,
       CHARACTER_SET_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME IN ('customer_entity', 'vendor_mapping')
  AND COLUMN_NAME IN ('email', 'external_email');

表的默认 collation 只影响新列,已有列可能仍保留旧值。因此 SHOW CREATE TABLE 与 information_schema 都要看。

连接设置也能制造冲突

SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
SELECT @@character_set_connection, @@collation_connection;

CLI 客户端、PHP PDO 与复制任务可能使用不同连接字符集。错误只在后台 Web 请求出现、CLI 不出现时,应比较两个连接,而不是立即转换全库。检查 env.php 数据库初始化命令和驱动选项,同时确认代理层没有改 session variables。

自定义表是高发区域

Magento 核心表通常遵循安装版本的数据库要求,手写 SQL 创建的扩展表可能继承服务器默认值。数据库服务器升级后默认 collation 改变,新建扩展表与旧核心列 join 就会冲突。修复应写入模块 declarative schema 或 patch,保证新环境也得到一致定义。

不要直接 CONVERT 全库

ALTER TABLE ... CONVERT TO CHARACTER SET 会重建大表、持锁、增加磁盘和复制压力,还可能改变唯一索引的比较规则。例如大小写或重音敏感性变化后,原本不同的两个值可能变成重复。先在副本统计冲突,估算表大小与额外空间,并设计回滚。

SELECT LOWER(email), COUNT(*)
FROM customer_entity
GROUP BY LOWER(email)
HAVING COUNT(*) > 1;

该查询只是检查一种可能的等价冲突,实际规则取决于目标 collation。大表执行前先看执行计划和资源窗口。

选择目标不能只看“最新”

目标字符集与 collation 必须符合当前 Magento/Adobe Commerce 版本和数据库版本支持范围。不要因为 MySQL 新默认值看起来更现代,就在未验证的情况下切到另一套排序规则。尤其要检查索引键长度、JSON、临时表和复制节点兼容性。

安全迁移步骤

先列出所有非目标 collation 的列;按实际 join 关系确定优先级;在恢复副本或预发布环境转换;运行 setup:upgrade、索引、导入、客户登录和搜索回归;生产环境按表大小安排在线 DDL 或维护窗口。转换后再次查询 information_schema,并检查慢查询是否因隐式转换而失去索引。

真正的修复不是让报错的那条 SQL 成功,而是让数据库默认值、现有列、应用连接和自定义 schema 使用一致且受支持的规则,确保下一次部署不会重新创建冲突表。