1. 问题描述
某银行客户从MySQL 5.7迁移到GreatSQL 8.0,要求迁移完成后生产数据回流到MySQL 5.7一段时间,以备紧急回切和数据对比。在进行回流测试时,在 GreatSQL 8.0 侧执行的存储过程,其 binlog 中记录了 SET @@session.character_set_client=255,255 对应的排序规则 utf8mb4_0900_ai_ci ,是 MySQL/GreatSQL 8.0 新引入的排序规则,MySQL 5.7 不能识别,导致slave端MySQL 5.7的SQL线程中断。
报错信息如下:
SQL
mysql > select * from performance_schema.replication_applier_status_by_worker limit 1\G
*************************** 1. row ***************************
CHANNEL_NAME:
WORKER_ID: 1
THREAD_ID: NULL
SERVICE_STATE: OFF
LAST_SEEN_TRANSACTION: 195bbb58-b72a-11f1-9e63-fa163e5eebc2:6
LAST_ERROR_NUMBER: 22
LAST_ERROR_MESSAGE: Worker 1 failed executing transaction '195bbb58-b72a-11f1-9e63-fa163e5eebc2:6' at master log binlog.000928, end_log_pos 119877602; Error 'Character set '#255' is not a compiled character set and is not specified in the '/data/actiondb/base/5.7.44/share/charsets/Index.xml' file' on query. Default database: 'xxx_yyy_batch'. Query: 'TRUNCATE TABLE OOOOO_ORDER'
LAST_ERROR_TIMESTAMP: 2026-10-15 04:29:20
1 row in set (0.00 sec)
解析该事务对应的binlog,信息如下:
SQL
SET @@SESSION.GTID_NEXT= '195bbb58-b72a-11f1-9e63-fa163e5eebc2:6'/*!*/;
# at 119877488
#261015 4:29:20 server id 1034607900 end_log_pos 119877602 CRC32 0x774776ac Query thread_id=3623014 exec_time=0 error_code=0 Xid = 13469999
use `xxx_yyy_batch`/*!*/;
SET TIMESTAMP=1792009760/*!*/;
SET @@session.pseudo_thread_id=3623014/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1168113664/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=255,@@session.collation_connection=45,@@session.collation_server=46/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
/*!80011 SET @@session.default_collation_for_utf8mb4=45*//*!*/;
TRUNCATE TABLE OOOOO_ORDER
/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
存储过程proc_rept_ooooo_order的创建信息如下:
SQL
GreatSQL > show create procedure proc_rept_ooooo_order\G
*************************** 1. row ***************************
Procedure: PROC_REPT_OOOOO_ORDER
sql_mode: STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
Create Procedure: CREATE DEFINER=`run_batch`@`%` PROCEDURE `PROC_REPT_OOOOO_ORDER`( IN PETLDATE CHAR(8),OUT PCODE INT,OUT PMSG VARCHAR (80))
BEGIN
......
CALL PPPP_SSS_RUN_BATCH_LOG ( PETLDATE, PRC_NAME, PRC_STEP, PRC_DESC );
TRUNCATE TABLE OOOOO_ORDER;
......
END
character_set_client: utf8mb4
collation_connection: utf8mb4_general_ci
Database Collation: utf8mb4_general_ci
1 row in set (0.00 sec)
2. 问题分析
2.1 实验验证:探究binlog中字符集信息的来源
- 在GreatSQL中,直接设置character_set_client、collation_connection、collation_server为特定的值(224,225,226),检查存储过程执行后的binlog信息。
SQL
GreatSQL > select * from information_schema.collations where CHARACTER_SET_NAME='utf8mb4';
+----------------------------+--------------------+-----+------------+-------------+---------+---------------+
| COLLATION_NAME | CHARACTER_SET_NAME | ID | IS_DEFAULT | IS_COMPILED | SORTLEN | PAD_ATTRIBUTE |
+----------------------------+--------------------+-----+------------+-------------+---------+---------------+
| utf8mb4_general_ci | utf8mb4 | 45 | | Yes | 1 | PAD SPACE |
| utf8mb4_bin | utf8mb4 | 46 | | Yes | 1 | PAD SPACE |
| utf8mb4_unicode_ci | utf8mb4 | 224 | | Yes | 8 | PAD SPACE |
| utf8mb4_icelandic_ci | utf8mb4 | 225 | | Yes | 8 | PAD SPACE |
| utf8mb4_latvian_ci | utf8mb4 | 226 | | Yes | 8 | PAD SPACE |
| utf8mb4_romanian_ci | utf8mb4 | 227 | | Yes | 8 | PAD SPACE |
| utf8mb4_slovenian_ci | utf8mb4 | 228 | | Yes | 8 | PAD SPACE |
......
GreatSQL > SET @@session.character_set_client=224,@@session.collation_connection=225,@@session.collation_server=226;
Query OK, 0 rows affected (0.02 sec)
GreatSQL > show variables like '%colla%';
+-------------------------------+----------------------+
| Variable_name | Value |
+-------------------------------+----------------------+
| collation_connection | utf8mb4_icelandic_ci |
| collation_database | utf8mb4_bin |
| collation_server | utf8mb4_latvian_ci |
| default_collation_for_utf8mb4 | utf8mb4_general_ci |
+-------------------------------+----------------------+
4 rows in set (0.06 sec)
GreatSQL > drop PROCEDURE testchar3;
Query OK, 0 rows affected (0.16 sec)
GreatSQL > CREATE PROCEDURE testchar3() truncate table test2 ;
Query OK, 0 rows affected (0.01 sec)
GreatSQL > show procedure status like 'testchar3';
+------+-----------+-----------+-----------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+
| Db | Name | Type | Definer | Modified | Created | Security_type | Comment | character_set_client | collation_connection | Database Collation |
+------+-----------+-----------+-----------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+
| test | testchar3 | PROCEDURE | greatdb@% | 2026-10-19 16:25:43 | 2026-10-19 16:25:43 | DEFINER | | utf8mb4 | utf8mb4_icelandic_ci | utf8mb4_bin |
+------+-----------+-----------+-----------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+
1 row in set (0.03 sec)
执行testchar3后的binlog信息:
SQL
SET @@SESSION.GTID_NEXT= '684af664-79a4-11f1-9869-00163e883d79:68'/*!*/;
# at 5739
#261019 16:26:54 server id 1004003306 end_log_pos 5838 CRC32 0x3be26de4 Query thread_id=93 exec_time=0 error_code=0 Xid = 484
use `test`/*!*/;
SET TIMESTAMP=1792398414/*!*/;
SET @@session.pseudo_thread_id=93/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1168113696/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=224,@@session.collation_connection=225,@@session.collation_server=226/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
/*!80011 SET @@session.default_collation_for_utf8mb4=45*//*!*/;
truncate table test2
/*!*/;
可看出:binlog中character_set_client来自存储过程创建时,指定的系统变量character_set_client的数字值(排序规则224)。
- 重新登录数据库,在collation_server=utf8mb4_bin(46)下运行存储过程testchar3,解析后binlog信息,binlog中其他信息未改变,只改变了@@session.collation_server=46 。
SQL
SET @@session.character_set_client=224,@@session.collation_connection=225,@@session.collation_server=46/*!*/;
可以得出:
binlog中记录的字符集排序规则信息来源:
character_set_client-- 存储过程定义时 的客户端排序规则(client_collation_id)。collation_connection-- 存储过程定义时 的连接排序规则(connection_collation_id)。collation_server-- 存储过程运行时 的服务器排序规则(collation_server)。
2.2 检查表routines的数据来源
那 information_schema.routines 里为什么只看到 character_set_client: utf8mb4(字符集名称),却看不到 224 这个数字?
检查information_schema.routines的创建信息:
SQL
GreatSQL > show create table information_schema.routines\G
*************************** 1. row ***************************
View: ROUTINES
Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`mysql.infoschema`@`localhost` SQL SECURITY DEFINER VIEW `ROUTINES` AS select `rtn`.`name` AS `SPECIFIC_NAME`,(`cat`.`name` collate utf8mb3_tolower_ci) AS `ROUTINE_CATALOG`,(`sch`.`name` collate utf8mb3_tolower_ci) AS `ROUTINE_SCHEMA`,`rtn`.`name` AS `ROUTINE_NAME`,`rtn`.`type` AS `ROUTINE_TYPE`,if((`rtn`.`type` <> 'FUNCTION'),'',substring_index(substring_index(`rtn`.`result_data_type_utf8`,'(',1),' ',1)) AS `DATA_TYPE`,internal_dd_char_length(`rtn`.`result_data_type`,`rtn`.`result_char_length`,`coll_result`.`name`,0) AS `CHARACTER_MAXIMUM_LENGTH`,internal_dd_char_length(`rtn`.`result_data_type`,`rtn`.`result_char_length`,`coll_result`.`name`,1) AS `CHARACTER_OCTET_LENGTH`,`rtn`.`result_numeric_precision` AS `NUMERIC_PRECISION`,`rtn`.`result_numeric_scale` AS `NUMERIC_SCALE`,`rtn`.`result_datetime_precision` AS `DATETIME_PRECISION`,(case `rtn`.`result_data_type` when 'MYSQL_TYPE_STRING' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_VAR_STRING' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_VARCHAR' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_TINY_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_MEDIUM_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_LONG_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_ENUM' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_SET' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) else NULL end) AS `CHARACTER_SET_NAME`,(case `rtn`.`result_data_type` when 'MYSQL_TYPE_STRING' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_VAR_STRING' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_VARCHAR' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_TINY_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_MEDIUM_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_LONG_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_ENUM' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_SET' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) else NULL end) AS `COLLATION_NAME`,if((`rtn`.`type` <> 'FUNCTION'),NULL,`rtn`.`result_data_type_utf8`) AS `DTD_IDENTIFIER`,'SQL' AS `ROUTINE_BODY`,if(can_access_routine(`sch`.`name`,`rtn`.`name`,`rtn`.`type`,`rtn`.`definer`,true),`rtn`.`definition_utf8`,NULL) AS `ROUTINE_DEFINITION`,NULL AS `EXTERNAL_NAME`,`rtn`.`external_language` AS `EXTERNAL_LANGUAGE`,'SQL' AS `PARAMETER_STYLE`,if((`rtn`.`is_deterministic` = 0),'NO','YES') AS `IS_DETERMINISTIC`,`rtn`.`sql_data_access` AS `SQL_DATA_ACCESS`,NULL AS `SQL_PATH`,`rtn`.`security_type` AS `SECURITY_TYPE`,`rtn`.`created` AS `CREATED`,`rtn`.`last_altered` AS `LAST_ALTERED`,`rtn`.`sql_mode` AS `SQL_MODE`,`rtn`.`comment` AS `ROUTINE_COMMENT`,`rtn`.`definer` AS `DEFINER`,`cs_client`.`name` AS `CHARACTER_SET_CLIENT`,`coll_conn`.`name` AS `COLLATION_CONNECTION`,`coll_db`.`name` AS `DATABASE_COLLATION` from ((((((((`mysql`.`routines` `rtn` join `mysql`.`schemata` `sch` on((`rtn`.`schema_id` = `sch`.`id`))) join `mysql`.`catalogs` `cat` on((`cat`.`id` = `sch`.`catalog_id`))) join `mysql`.`collations` `coll_client` on((`coll_client`.`id` = `rtn`.`client_collation_id`))) join `mysql`.`character_sets` `cs_client` on((`cs_client`.`id` = `coll_client`.`character_set_id`))) join `mysql`.`collations` `coll_conn` on((`coll_conn`.`id` = `rtn`.`connection_collation_id`))) join `mysql`.`collations` `coll_db` on((`coll_db`.`id` = `rtn`.`schema_collation_id`))) left join `mysql`.`collations` `coll_result` on((`coll_result`.`id` = `rtn`.`result_collation_id`))) left join `mysql`.`character_sets` `cs_result` on((`cs_result`.`id` = `coll_result`.`character_set_id`))) where (0 <> can_access_routine(`sch`.`name`,`rtn`.`name`,`rtn`.`type`,`rtn`.`definer`,false))
character_set_client: utf8mb3
collation_connection: utf8mb3_general_ci
1 row in set (0.00 sec)
由视图的构建可知:
information_schema.routines是源于mysql.routines,在mysql.routines中存储的是client_collation_id(客户端排序规则),但在information_schema.routines中CHARACTER_SET_NAME 显示的不是client_collation_id(排序规则),而是其对应的字符集名称。
SQL
information_schema.routines(CHARACTER_SET_CLIENT)
▲
│ select cs_client.name AS CHARACTER_SET_CLIENT
mysql.character_sets(character_set_id,name) cs_client
▲ on cs_client.id = coll_client.character_set_id
│
mysql.collations(id) coll_client
▲ on coll_client.id = rtn.client_collation_id
│
mysql.routines(client_collation_id) rtn
2.3 处理方法
解决存储过程使用utf8mb4_0900_ai_ci(255)导致无法回流到MySQL 5.7的问题,可以在GreatDB中,在MySQL 5.7识别的character_set_client下,重新创建存储过程。
如:在utf8mb4_bin下重新创建存储过程:
SQL
-- 1、设置会话的character_set_client
set names utf8mb4 collate utf8mb4_bin;
-- 或者直接设置character_set_client
SET @@session.character_set_client=46; -- 排序规则utf8mb4_bin
-- 2、重新编译存储过程和函数
drop procedure xxxx ;
create procedure xxxx ....
3. 总结
由于GreatSQL与MySQL高度兼容,MySQL 5.7迁移到GreatSQL 8.0的步骤比较简单,可以使用GreatSQL 8.0软件可以直接打开MySQL 5.7的数据库文件,GreatSQL 8.0实例启动时会自动完成数据库字典的升级。
升级后,如果需要异步复制方式从GreatSQL 8.0回流到MySQL 5.7,请注意不能在GreatSQL 8.0执行MySQL5.7不识别的命令、不能使用MySQL 5.7 不识别的字符集和排序规则。由于升级后的存储程序(包括:存储过程procedure、函数function、自动调度事件event)中记录的排序规则是 utf8mb4 的默认排序规则utf8mb4_0900_ai_ci(编号255),属于MySQL 5.7不识别的排序规则,这些存储程序需要在MySQL 5.7识别的排序规则下重新创建。