Mysql升级后字符编码引起的血泪教训

描述

现在大部分企业所使用的MySQL数据库相信都已经从5.7升级到了8,性能也得到了大幅度的提升

MySQL 8.0对于数据管理带来了很多改变,使得MySQL成为一个更强大、更灵活和更易于使用的数据库管理系统。

  1. MySQL 8.0提供了更好的JSON支持,包括更快的JSON函数和表达式,以及新的JSON数据类型和索引。

  2. MySQL 8.0引入了窗口函数,这些函数可以用来计算分析函数的结果并根据指定的排序规则进行分组。

  3. MySQL 8.0提供了更好的空间数据支持,包括新的空间数据类型和函数,例如ST_Distance_Sphere函数,它可以计算两个点之间的球面距离。

  4. MySQL 8.0提供了更好的安全性,包括更安全的默认配置、更严格的密码策略、更多的SSL/TLS选项等。

  5. MySQL 8.0提供了更好的性能,包括新的索引算法、更好的查询优化器、更好的并发控制等。

MySQL5.7

查看版本号
查看编码格式

从结果可以看出,MySQL8默认字符编码为utf8mb4

查看排序规则

从结果可以看出,MySQL8默认排序规则为utf8mb4_general_ci

总结

MySQL5.7 默认字符编码是utf8mb4,默认排序规则是utf8mb4_general_ci

MySQL8

查看版本号
查看编码格式

"character_set_client" 表示客户端字符集

"character_set_connection" 表示连接字符集

"character_set_server" 表示服务器字符集

从结果可以看出,MySQL8默认字符编码为utf8mb4

查看排序规则

从结果可以看出,MySQL8默认排序规则为utf8mb4_0900_ai_ci

总结

MySQL8 默认字符编码是utf8mb4,默认排序规则是utf8mb4_0900_ai_ci

utf8 与 utf8mb4 区别

  1. 存储字符范围不同:

    • utf8 编码最多能存储 3 个字节的 Unicode 字符,支持的 Unicode 范围较窄,无法存储一些辅助平面字符(如 emoji 表情)。
    • utf8mb4 编码最多能存储 4 个字节的 Unicode 字符,支持更广泛的 Unicode 范围,包括了 utf8 所不支持的一些特殊字符和 emoji 表情等。
  2. 存储空间不同:

    • utf8 编码时,字符长度可以是最多 3 个字节。
    • utf8mb4 编码时,字符长度可以是最多 4 个字节。
  3. 对于存储 Emoji 和特殊字符的支持:

    • utf8mb4 能够存储和处理来自辅助平面的字符,包括emoji表情,这些字符需要使用 4 个字节来编码。而 utf8 不支持这些字符。

utf8mb4_general_ci 与 utf8mb4_0900_ai_ci 区别

  1. utf8mb4_general_ci

    • 这是MySQL中较为通用的字符集和校对规则。
    • utf8mb4 是一种用于存储 Unicode 字符的编码方式,支持更广泛的字符范围,包括 emoji 等。
    • general_ci 是一种排序规则,对字符进行比较和排序时不区分大小写,对于大多数情况来说是足够通用的。
  2. utf8mb4_0900_ai_ci

    • 这是MySQL 8.0.0 版本后引入的校对规则。
    • 0900 表示MySQL 8.0.0 版本。
    • ai_ci 是指采用 accent-insensitive 方式,即对于一些有重音符号的字符,排序时会忽略重音的存在。

主要区别在于排序规则的不同。utf8mb4_0900_ai_ci 在排序时会对重音符号进行忽略,所以某些含有重音符号的字符在排序时可能会与 utf8mb4_general_ci 有所不同。

索引不生效问题

表结构
sql 复制代码
CREATE TABLE `user` (
 `id` bigint NOT NULL COMMENT '主键',
 `username` varchar(50) NOT NULL DEFAULT '' COMMENT '名称',
 `password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
 `store_id` bigint NOT NULL DEFAULT 0 COMMENT '门店id',
 `is_delete` int NOT NULL DEFAULT '0' COMMENT '是否删除',
 PRIMARY KEY (`id`),
 KEY `idx_store_id` (`store_id`)
) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';


CREATE TABLE `user_role` (
 `id` bigint NOT NULL COMMENT '主键',
 `user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户id',
 `role_id` bigint NOT NULL DEFAULT 0 COMMENT '角色id',
 `is_delete` int NOT NULL DEFAULT '0' COMMENT '是否删除',
 PRIMARY KEY (`id`),
 KEY `idx_user_id` (`user_id`),
 KEY `idx_role_id` (`role_id`)
) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户角色关系表';
查询
sql 复制代码
SELECT DISTINCT
	t1.id,
	t1.username 
FROM
	user t1
	JOIN user_role t2 ON t2.user_id = t1.id 
WHERE
	t1.is_delete = 0
	and t2.is_delete = 0
	and t1.store_id = 2 
	AND t2.role_id NOT IN (9, 6)
执行计划

通过执行计划发现明明字段上加了索引,为什么索引没有生效

explain format = tree 命令
问题找到了

(convert(t2.user_id using utf8mb4) = t1.id))

在回头看看表结构
为什么会不一致呢?

mysql5.7 升级之前 两个表都是 CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

mysql5.7 升级到 mysql8 后,user_role 更新过表结构

修改表排序规则

ALTER TABLE user CHARACTER COLLATE = utf8mb4_0900_ai_ci;

再次查看执行计划
总结

开发一般都不太注意表结构的字符编码和排序规则,数据库升级一定要先统一字符编码和排序规则

查询的问题

由于先发布应用,后执行的脚步,没有通知测试所以没有生产验证,导致第二天一大早疯狂报警

一看就是两个表字段排序规则不一致导致的

只能修改表结构排序规则 快速解决

总结

升级MySQL是一个常见的操作,但在升级过程中可能会遇到各种问题。本文主要介绍排序规则不一致导致的问题,希望能对大家在升级MySQL时有所帮助。在进行任何升级操作之前,务必备份数据库,以防数据丢失。同时,建议定期对数据库进行性能优化,以提高系统的高可用。

相关推荐
sdg_advance2 分钟前
Spring Cloud之OpenFeign的具体实践
后端·spring cloud·openfeign
碳苯1 小时前
【rCore OS 开源操作系统】Rust 枚举与模式匹配
开发语言·人工智能·后端·rust·操作系统·os
kylinxjd1 小时前
spring boot发送邮件
java·spring boot·后端·发送email邮件
2401_857439694 小时前
Spring Boot新闻推荐系统:用户体验优化
spring boot·后端·ux
进击的女IT5 小时前
SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS
java·spring boot·后端
一 乐6 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
艾伦~耶格尔9 小时前
Spring Boot 三层架构开发模式入门
java·spring boot·后端·架构·三层架构
man20179 小时前
基于spring boot的篮球论坛系统
java·spring boot·后端
攸攸太上10 小时前
Spring Gateway学习
java·后端·学习·spring·微服务·gateway
罗曼蒂克在消亡10 小时前
graphql--快速了解graphql特点
后端·graphql