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引发的惨案相关推荐

  1. mysql修改字符集utf8为utf8mb4

    mysql修改字符集utf8为utf8mb4 查看数据库的编码格式 1 2 3 SHOW VARIABLES WHERE Variable_name LIKE 'character_set_%' OR ...

  2. MySQL修改字符集

    MySQL数据库修改字符集,介绍一下修改的方法 1)系统工具iconv #file filename #mysqldump --default-character-set=utf8 >20180 ...

  3. MySQL修改字符集步骤(字段插入中文提示错误时解决办法)

    在实际应用中,如果一开始没有正确的设置字符集,在运行一段时间以后,才发现当前字符集不能满足要求,需要进行调整,但又不想丢弃这段时间的数据,这个时候就需要修改字符集. 在<MySQL设置默认字符集 ...

  4. mysql修改字符集_MySQL修改字符集步骤详解

    在实际应用中,如果一开始没有正确的设置字符集,在运行一段时间以后,才发现当前字符集不能满足要求,需要进行调整,但又不想丢弃这段时间的数据,这个时候就需要修改字符集. 在<MySQL设置默认字符集 ...

  5. mysql 修改字符集为utf8mb4_MySQL数据库修改字符集为utf8mb4

    需要修改my.ini( my.cnf) [client] default-character-set=utf8mb4 [mysqld] character-set-client-handshake = ...

  6. linux下mysql修改字符集,远程连接

    安装时候很简单,但是安装了后一般不能用 安装后 首先执行 mysql -u root mysql 这是就会进入mysql命令窗口,这样是可以使用的,但是我们要先设置密码 1.先设置密码 UPDATE ...

  7. ubuntu mysql修改字符集后不能启动mysql_解决ubuntu下修改my.cnf设置字符集导致mysql无法启动...

    在Ubuntu下安装了MySQL数据库,为了便于使用,欲将字符集统一设置为utf8,而不是默认的latin1. 进入mysql,输入show variables like 'character%';查 ...

  8. linux mysql 修改字符集_linux下mysql修改字符集,远程连接

    安装时候很简单,但是安装了后一般不能用 安装后 首先执行 mysql -u root mysql 这是就会进入mysql命令窗口,这样是可以使用的,但是我们要先设置密码 1.先设置密码 UPDATE ...

  9. mysql修改字符集utf8_修改mysql数据库字符集为UTF8

    第一种 一.修改my.ini配置文件(MySQL配置文件) character_set_server = utf8 #设置字符集 重启mysql数据库服务 查看当前数据库字符集 show VARIAB ...

最新文章

  1. Java中Set集合是如何实现添加元素保证不重复的?
  2. 20145201李子璇 《网络对抗》恶意代码分析
  3. 人类史上首张黑洞照片发布!
  4. 理解注意力机制的好文二
  5. Python中的网络编程之UDP
  6. 信息学奥赛一本通C++语言——1014:与圆相关的计算
  7. 软件测试面试-测试的目的是什么?【高频】
  8. java string对象名称_java中常见对象——String
  9. Vue如何mock数据模拟Ajax请求
  10. 产品学习---互联网思维
  11. TFS2010学习之一
  12. 如何制作扫描连接WIFI二维码,手机扫码即可一键连接无线WIFI网络
  13. python排版_python排版
  14. 如何为您的ADC选择最合适的基准电压源和放大器
  15. mybatis获取map中的key和value
  16. 圣诞节蓝牙耳机选哪款作为礼物比较好?耐用的蓝牙耳机推荐
  17. 强基计划 数学相关书籍 推荐
  18. h5上传图片html5,h5图片上传简易版(FileReader+FormData+ajax)
  19. (七)Java游戏部署在Palm Os平台仿真器(Access)
  20. [ Android实战 ] java.lang.UnsatisfiedLinkError: No implementation found for xxx 问题解决

热门文章

  1. 云原生数据库设计新思路
  2. 回顾数据结构的基础知识
  3. 基于Levenberg-Marquardt算法的加速度计标定方法
  4. 层次分析法-基于节点关键度的DTN路由算法
  5. 迁移废弃的Kotlin Android Extensions插件
  6. linux telnet: command not found,提示-bash: telnet: command not found的解决方法
  7. 飞信Fetion历史数据库研究(History.dat)——嵌入式数据库SQLite介绍(转)
  8. 部分ERP软件技术指标分析报告
  9. 基于双目视觉的移动机器人SLAM系统研究与设计
  10. 华裔科学家Ashe教授对涉嫌造假的Nature论文的正面回应