MySQL 5.7升级8.0后,排序规则问题解决方案汇总
比较操作中使用不同的字符集或排序规则通常会触发此问题,MySQL 8.0 默认 COLLATE 为 utf8mb4_0900_ai_ci
和 对应列 COLLATE 的 utf8mb4_general_ci
不匹配。
> 作者:陈举超
问题现象
MySQL 5.7.34 升级到 8.0.32 后部分查询语句报错如下:
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation 'find_in_set'
问题原因
比较操作中使用不同的字符集或排序规则通常会触发此问题,MySQL 8.0 默认 COLLATE 为 utf8mb4_0900_ai_ci
和 对应列 COLLATE 的 utf8mb4_general_ci
不匹配。
问题重现过程
创建测试表。
CREATE TABLE `t01` ( `ID` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `A_CODE` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `B_CODE` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
执行查询语句。
SELECT AAA.* FROM( SELECT @xxx AS _xxx, ( SELECT @xxx := GROUP_CONCAT( A_CODE ) FROM t01 WHERE FIND_IN_SET( B_CODE, @xxx ) ) AS cxxx FROM t01,( SELECT @xxx := 'xxx') b WHERE @xxx IS NOT NULL) ID,t01 AAA WHERE FIND_IN_SET( AAA.A_CODE, ID._xxx ) order by A_CODE;
报错。
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation 'find_in_set'
问题分析
查看默认排序规则。
mysql> show collation like 'utf8mb4_0900_ai_ci'; +--------------------+---------+-----+---------+----------+---------+---------------+ | Collation | Charset | Id | Default | Compiled | Sortlen | Pad_attribute | +--------------------+---------+-----+---------+----------+---------+---------------+ | utf8mb4_0900_ai_ci | utf8mb4 | 255 | Yes | Yes | 0 | NO PAD | +--------------------+---------+-----+---------+----------+---------+---------------+ 1 row in set (0.00 sec) mysql> show collation like 'utf8mb4_general_ci'; +--------------------+---------+----+---------+----------+---------+---------------+ | Collation | Charset | Id | Default | Compiled | Sortlen | Pad_attribute | +--------------------+---------+----+---------+----------+---------+---------------+ | utf8mb4_general_ci | utf8mb4 | 45 | | Yes | 1 | PAD SPACE | +--------------------+---------+----+---------+----------+---------+---------------+ 1 row in set (0.00 sec) mysql> SELECT * FROM INFORMATION_SCHEMA.COLLATIONS WHERE IS_DEFAULT='Yes' and CHARACTER_SET_NAME='utf8mb4'; +--------------------+--------------------+-----+------------+-------------+---------+---------------+ | COLLATION_NAME | CHARACTER_SET_NAME | ID | IS_DEFAULT | IS_COMPILED | SORTLEN | PAD_ATTRIBUTE | +--------------------+--------------------+-----+------------+-------------+---------+---------------+ | utf8mb4_0900_ai_ci | utf8mb4 | 255 | Yes | Yes | 0 | NO PAD | +--------------------+--------------------+-----+------------+-------------+---------+---------------+ 1 row in set (0.00 sec)
查看相关参数。
mysql> show variables like '%collation%'; +-------------------------------+--------------------+ | Variable_name | Value | +-------------------------------+--------------------+ | collation_connection | utf8mb4_0900_ai_ci | | collation_database | utf8mb4_general_ci | | collation_server | utf8mb4_general_ci | | default_collation_for_utf8mb4 | utf8mb4_0900_ai_ci | +-------------------------------+--------------------+ 4 rows in set (0.00 sec) 其中: mysql> show global variables like '%collation%'; +-------------------------------+--------------------+ | Variable_name | Value | +-------------------------------+--------------------+ | collation_connection | utf8mb4_general_ci | | collation_database | utf8mb4_general_ci | | collation_server | utf8mb4_general_ci | | default_collation_for_utf8mb4 | utf8mb4_0900_ai_ci | +-------------------------------+--------------------+ 4 rows in set (0.00 sec)
查看配置文件参数。
mysql@CJC-DB-01:/home/mysql$cat /etc/my.cnf ...... [mysqld] collation_server = utf8mb4_general_ci
可以看到,客户端局部会话变量 collation_connection 的值为 utf8mb4_0900_ai_ci
,而全局变量值为 utf8mb4_general_ci
,两者不一致。
这是由于服务端在客户端连接时,获取了客户端对字符集和排序规则的缺省设置,也就是 utf8mb4_0900_ai_ci
。
解决方案
- 修改参数
- 修改表 COLLATE
- 修改 SQL 语句
1. 修改参数
参数collation_connection
在客户端局部变量值和全局变量值不一致,如何改成一致?官网参考材料
--character-set-client-handshake Command-Line Format:--character-set-client-handshake[={OFF|ON}] Deprecated:8.0.35 Type:Boolean Default Value:ON
参数说明
- 不忽略客户端发送的字符集信息
- 为了忽略客户端信息并使用默认的服务器字符集
- 使用参数:
--skip-character-set-client-handshake
此选项在 MySQL 8.0.35 及更高版本的 MySQL 8.0 中已被弃用。在该版本中,无论何时使用此选项,都会发出警告,并将在未来版本的 MySQL 中删除。
依赖此选项的应用程序应该尽快开始迁移。
添加 my.cnf 参数。
[mysqld] skip-character-set-client-handshake
重启 MySQL。
mysqladmin -uroot -p****** shutdown mysqld --defaults-file=/etc/my.cnf --user=mysql & 登录 mysql -uroot -p cjc 查看参数,collation_connection 参数值修改成功 mysql> show global variables like '%collation%'; +-------------------------------+--------------------+ | Variable_name | Value | +-------------------------------+--------------------+ | collation_connection | utf8mb4_general_ci | | collation_database | utf8mb4_general_ci | | collation_server | utf8mb4_general_ci | | default_collation_for_utf8mb4 | utf8mb4_0900_ai_ci | +-------------------------------+--------------------+ 4 rows in set (0.00 sec) mysql> show variables like '%collation%'; +-------------------------------+--------------------+ | Variable_name | Value | +-------------------------------+--------------------+ | collation_connection | utf8mb4_general_ci | | collation_database | utf8mb4_general_ci | | collation_server | utf8mb4_general_ci | | default_collation_for_utf8mb4 | utf8mb4_0900_ai_ci | +-------------------------------+--------------------+ 4 rows in set (0.01 sec)
再次执行,问题解决。
SELECT AAA.* FROM( SELECT @xxx AS _xxx, ( SELECT @xxx := GROUP_CONCAT( A_CODE ) FROM t01 WHERE FIND_IN_SET( B_CODE, @xxx ) ) AS cxxx FROM t01,( SELECT @xxx := 'xxx') b WHERE @xxx IS NOT NULL) ID,t01 AAA WHERE FIND_IN_SET( AAA.A_CODE, ID._xxx ) order by A_CODE; Empty set, 2 warnings (0.00 sec)
2. 修改表 COLLATE
先改回原参数,查询报错。
SELECT AAA.* FROM( SELECT @xxx AS _xxx, ( SELECT @xxx := GROUP_CONCAT( A_CODE ) FROM t01 WHERE FIND_IN_SET( B_CODE, @xxx ) ) AS cxxx FROM t01,( SELECT @xxx := 'xxx') b WHERE @xxx IS NOT NULL) ID,t01 AAA WHERE FIND_IN_SET( AAA.A_CODE, ID._xxx ) order by A_CODE; ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation 'find_in_set'
修改表排序规则。
mysql> show create table t01\G; *************************** 1. row *************************** Table: t01 Create Table: CREATE TABLE `t01` ( `ID` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `A_CODE` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `B_CODE` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC 1 row in set (0.00 sec) ERROR: No query specified
修改所有列 COLLATE,实际上只修改 A_CODE
、B_CODE
列 COLLATE 也可解决此问题。
ALTER TABLE cjc.t01 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; ALTER TABLE cjc.t01 MODIFY COLUMN `ID` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL; ALTER TABLE cjc.t01 MODIFY COLUMN `A_CODE` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL; ALTER TABLE cjc.t01 MODIFY COLUMN `B_CODE` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL;
再次执行,问题解决。
SELECT AAA.* FROM( SELECT @xxx AS _xxx, ( SELECT @xxx := GROUP_CONCAT( A_CODE ) FROM t01 WHERE FIND_IN_SET( B_CODE, @xxx ) ) AS cxxx FROM t01,( SELECT @xxx := 'xxx') b WHERE @xxx IS NOT NULL) ID,t01 AAA WHERE FIND_IN_SET( AAA.A_CODE, ID._xxx ) order by A_CODE; Empty set, 2 warnings (0.00 sec)
查看表结构。
mysql> show create table t01\G; *************************** 1. row *************************** Table: t01 Create Table: CREATE TABLE `t01` ( `ID` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `A_CODE` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `B_CODE` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, PRIMARY KEY (`ID`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC 1 row in set (0.00 sec)
3. 修改 SQL 语句
将 A_CODE
,B_CODE
列的 COLLATE 在 SQL 语句中转换为 utf8mb4_0900_ai_ci
。
改写后的SQL如下:
SELECT AAA.* FROM( SELECT @xxx AS _xxx, ( SELECT @xxx := GROUP_CONCAT( A_CODE COLLATE utf8mb4_0900_ai_ci ) FROM t01 WHERE FIND_IN_SET( B_CODE COLLATE utf8mb4_0900_ai_ci, @xxx ) ) AS cxxx FROM t01,( SELECT @xxx := 'xxx') b WHERE @xxx IS NOT NULL) ID,t01 AAA WHERE FIND_IN_SET( AAA.A_CODE COLLATE utf8mb4_0900_ai_ci, ID._xxx ) order by A_CODE;
总结
比较三种解决方案,每种解决方案适用场景不同,请根据实际情况选择解决方案。
-
修改参数
适用于数据库是从 5.7 或更低版本升级到 8.0,并且表数量较多、数据量加大。不适用于批量修改所有表、列字符集和排序规则。
-
修改表 COLLATE
适用于修改过程会锁表,数据量越大时间越长,使用于数据量小的场景,建议将所有表、列字符集和排序规则改成 8.0 默认值,后续新增表时不指定字符集和排序规则。
-
修改 SQL 语句
适用于临时查询,改SQL影响最小。
更多技术文章,请访问:https://opensource.actionsky.com/
关于 SQLE
SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。
✨ Github:https://github.com/actiontech/sqle
📚 文档:https://actiontech.github.io/sqle-docs/
💻 官网:https://opensource.actionsky.com/sqle/
👥 微信群:请添加小助手加入 ActionOpenSource

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
ByConity 在抖音集团内行为分析 EB 级场景的最佳实践
ByConity是字节跳动基于ClickHouse发展出的存算分离的云原生数仓引擎,2023年1月正式发布开源Beta版本,今年7月,ByConity正式发布1.0版本。 开源一周年之际,ByConity已经获得了2100+的Star数,issue数480+,用户60+,贡献者80+。2024年5月25日,ByConity一周年线下meetup在北京召开。本期主题是《云原生数仓创新之路》,多位重磅嘉宾出席并分享了 ByConity的最佳实践。 来自抖音集团的行为分析平台的何皓星分享了使用ByConity解决线上业务场景和和自身架构迭代的实践经验。 何皓星介绍,抖音内部有自己的数据分析产品——DataFinder,提供了一站式的数据采集、数仓分析、结果展示平台,支持产品使用行为数据实时采集和自助建模、分析、结果分享、数据监控,运营分析师上手就能用。目前,在抖音内部已经广泛使用,为包括抖音、今日头条、西瓜视频、剪映在内的上千个产品提供分析能力,EB级别上报量大数据量达秒级响应。 起初,字节内使用Kylin & Spark SQL等架构支持业务,但当产品、维度变多,他们遇到了数据支撑...
- 下一篇
vxe-table 4.7.37 已经发布,vue 表格解决方案
vxe-table 4.7.37 已经发布,vue 表格解决方案 此版本更新内容包括: 兼容老版本 table 修复复选框和单选框不显示问题 优化导入导入 详情查看:https://gitee.com/xuliangzhan_admin/vxe-table/releases/4.7.37
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS8安装Docker,最新的服务器搭配容器使用
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2全家桶,快速入门学习开发网站教程