mysql修改字符集utf8mb4引发的惨案
mysql修改字符集utf8mb4引发的惨案
- 环境配置: Linux CentOS 7 mysql5.7字符编码是utf8;
- 惨案原因:数据库表需要支持表情很符号,表情符号一般是4个字符,utf8最多支持3个字符,如果插入表情符号4个字符的字段就会报错,因此我们修改了此表的字符集为utf8mb4,在这说明一下utf8mb4是utf8的超集。
- 问题来了:MySQL环境上有两张表做left join时使用的字段都索引,但是执行计划里面显示有一张表使用了全表扫描,扫描全表近百万行记录,导致sql执行很慢。
- 诊断结果:是mysql表修改字符集utf8mb4引发的惨案;
- 问题诊断重现:首先,表结构和表记录如下:
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`code` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_code` (`code`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
t1 插入一些数据
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`code` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_code` (`code`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4
t2插入一些数据
2张表left join的执行计划如下:
desc select * from t2 join t1 on t1.code = t2.code where t2.name = 'dddd'\G;
可以明显地看到,t2.name ='dddd’使用了索引,而t1.code = t2.code这个关联条件没有使用到t1.code上面的索引,一开 始也百思不得其解,但是机器不会骗人。显示警告查看
查询执行计划的告警信息:
show warnings;
发现问题:在发现了转换(使用utf8mb4的testdb.t1.code)之后,Scott发现2个表的字符集不一样。t1为utf8,t2为utf8mb4。但是为什么表表字符集不一样(实际是我修改了字符集 字符串字符集不一样了)就会导致T1全表扫描呢?下面来做分析。
(1)首先t2左联接t1决定了t2是驱动表,此步相当于执行了选择* from t2 where t2.name =‘dddd’,取码范围的值,这里为’8a77a32a7e0825f7c8634226105c42e5’;
(2)然后拿起t2查到的代码的值根据联接条件去t1里面查找,这一步就相当于执行了select * from t1 where t1.code =‘8a77a32a7e0825f7c8634226105c42e5’;
(3)但是由于第(1)步里面T2表取出的代码字段是utf8mb4字符集,而T1表里面的代码是UTF8字符集,这里需要做字符集转换,字符集转换遵循由小到大的原则,因为utf8mb4是UTF8的超集,所以这里把UTF8转换成utf8mb4,即把t1.code转换成utf8mb4字符集,转换了之后,由于t1.code上面的索引仍然是UTF8字符集,所以这个索引就被执行计划忽略了,然后T1表只能选择全表扫描。更糟糕的是,如果T2筛选出来的记录不止1条,那么T1就会被全表扫描多次,性能之差可想而知。解决问题:
既然原因已经清楚了,如何解决呢?当然是改字符集了,把T1改成和T2一样或者把T2改成T1都可以,这里选择把T1转成utf8mb4。那怎么转字符集呢?
有一个同学会说用alter table t1 charset utf8mb4;而是错的,这只是改了表的替代字符集,即新的数据才会使用utf8mb4,已经存在的一部分仍然是utf8。
用只有alter table t1 convert to charset utf8mb4;才是正确的。
但是还要注意一点,更改表改字符集的操作是双重写的(用lock = node会报错)所以业务高峰时请不要操作,即使在业务低峰时期,大表的操作仍建议使用pt-online -schema改变在线修改字符集。
测试环境:使用 alter table t1 convert to charset utf8mb4, lock=shared;
现在再来查看执行计划,可以看到已经没问题了。
- 复盘总结:
1、 表字符集不同时,可能导致加入的SQL使用不到索引,引起严重的性能问题;
2、 改字符集的alter table操作会多个写,业务mysql建议使用pt-online-schema-change;
3、 如果要大批量修改表的字符集,同样做好SQL的审议工作,关联的表的字符集一起做修改。
4、 效仿一下使用show warnings【千万不能忘】
mysql修改字符集utf8mb4引发的惨案相关推荐
- mysql修改字符集utf8为utf8mb4
mysql修改字符集utf8为utf8mb4 查看数据库的编码格式 1 2 3 SHOW VARIABLES WHERE Variable_name LIKE 'character_set_%' OR ...
- MySQL修改字符集
MySQL数据库修改字符集,介绍一下修改的方法 1)系统工具iconv #file filename #mysqldump --default-character-set=utf8 >20180 ...
- MySQL修改字符集步骤(字段插入中文提示错误时解决办法)
在实际应用中,如果一开始没有正确的设置字符集,在运行一段时间以后,才发现当前字符集不能满足要求,需要进行调整,但又不想丢弃这段时间的数据,这个时候就需要修改字符集. 在<MySQL设置默认字符集 ...
- mysql修改字符集_MySQL修改字符集步骤详解
在实际应用中,如果一开始没有正确的设置字符集,在运行一段时间以后,才发现当前字符集不能满足要求,需要进行调整,但又不想丢弃这段时间的数据,这个时候就需要修改字符集. 在<MySQL设置默认字符集 ...
- mysql 修改字符集为utf8mb4_MySQL数据库修改字符集为utf8mb4
需要修改my.ini( my.cnf) [client] default-character-set=utf8mb4 [mysqld] character-set-client-handshake = ...
- linux下mysql修改字符集,远程连接
安装时候很简单,但是安装了后一般不能用 安装后 首先执行 mysql -u root mysql 这是就会进入mysql命令窗口,这样是可以使用的,但是我们要先设置密码 1.先设置密码 UPDATE ...
- ubuntu mysql修改字符集后不能启动mysql_解决ubuntu下修改my.cnf设置字符集导致mysql无法启动...
在Ubuntu下安装了MySQL数据库,为了便于使用,欲将字符集统一设置为utf8,而不是默认的latin1. 进入mysql,输入show variables like 'character%';查 ...
- linux mysql 修改字符集_linux下mysql修改字符集,远程连接
安装时候很简单,但是安装了后一般不能用 安装后 首先执行 mysql -u root mysql 这是就会进入mysql命令窗口,这样是可以使用的,但是我们要先设置密码 1.先设置密码 UPDATE ...
- mysql修改字符集utf8_修改mysql数据库字符集为UTF8
第一种 一.修改my.ini配置文件(MySQL配置文件) character_set_server = utf8 #设置字符集 重启mysql数据库服务 查看当前数据库字符集 show VARIAB ...
最新文章
- Java中Set集合是如何实现添加元素保证不重复的?
- 20145201李子璇 《网络对抗》恶意代码分析
- 人类史上首张黑洞照片发布!
- 理解注意力机制的好文二
- Python中的网络编程之UDP
- 信息学奥赛一本通C++语言——1014:与圆相关的计算
- 软件测试面试-测试的目的是什么?【高频】
- java string对象名称_java中常见对象——String
- Vue如何mock数据模拟Ajax请求
- 产品学习---互联网思维
- TFS2010学习之一
- 如何制作扫描连接WIFI二维码,手机扫码即可一键连接无线WIFI网络
- python排版_python排版
- 如何为您的ADC选择最合适的基准电压源和放大器
- mybatis获取map中的key和value
- 圣诞节蓝牙耳机选哪款作为礼物比较好?耐用的蓝牙耳机推荐
- 强基计划 数学相关书籍 推荐
- h5上传图片html5,h5图片上传简易版(FileReader+FormData+ajax)
- (七)Java游戏部署在Palm Os平台仿真器(Access)
- [ Android实战 ] java.lang.UnsatisfiedLinkError: No implementation found for xxx 问题解决
热门文章
- 云原生数据库设计新思路
- 回顾数据结构的基础知识
- 基于Levenberg-Marquardt算法的加速度计标定方法
- 层次分析法-基于节点关键度的DTN路由算法
- 迁移废弃的Kotlin Android Extensions插件
- linux telnet: command not found,提示-bash: telnet: command not found的解决方法
- 飞信Fetion历史数据库研究(History.dat)——嵌入式数据库SQLite介绍(转)
- 部分ERP软件技术指标分析报告
- 基于双目视觉的移动机器人SLAM系统研究与设计
- 华裔科学家Ashe教授对涉嫌造假的Nature论文的正面回应