1. 概述

昨天在一位同学的MySQL机器上面发现了这样一个问题,MySQL两张表做left join时,执行计划里面显示有一张表使用了全表扫描,扫描全表近100万行记录,大并发的这样的SQL过来数据库变得几乎不可用了,今天和大家一起分享下这个问题的原因及解决办法,希望可以帮助大家更好的学习MySQL数据库,一起来看看吧。MySQL版本为官方5.7.13。

2. 问题重现

首先创建表:

插入测试数据:

2张表left join的执行计划如下:

可以明显地看到,t2.name = 'dddd'使用了索引,而t1.code = t2.code这个关联条件没有使用到t1.code上面的索引,一开始Scott也百思不得其解,但是机器不会骗人。Scott用show warnings查看改写后的执行计划如下:

在发现了convert(testdb.t1.code using utf8mb4)之后,Scott发现2个表的字符集不一样。t1为utf8,t2为utf8mb4。但是为什么表字符集不一样(实际是字段字符集不一样)就会导致t1全表扫描呢?下面来做分析。

(1)首先t2 left join t1决定了t2是驱动表,这一步相当于执行了select * from t2 where t2.name = ‘dddd’,取出code字段的值,这里为’8a77a32a7e0825f7c8634226105c42e5’;

(2)然后拿t2查到的code的值根据join条件去t1里面查找,这一步就相当于执行了select * from t1 where t1.code = ‘8a77a32a7e0825f7c8634226105c42e5’;

(3)但是由于第(1)步里面t2表取出的code字段是utf8mb4字符集,而t1表里面的code是utf8字符集,这里需要做字符集转换,字符集转换遵循由小到大的原则,因为utf8mb4是utf8的超集,所以这里把utf8转换成utf8mb4,即把t1.code转换成utf8mb4字符集,转换了之后,由于t1.code上面的索引仍然是utf8字符集,所以这个索引就被执行计划忽略了,然后t1表只能选择全表扫描。更糟糕的是,如果t2筛选出来的记录不止1条,那么t1就会被全表扫描多次,性能之差可想而知。

3. 问题解决

既然原因已经清楚了,如何解决呢?当然是改字符集了,把t1改成和t2一样或者把t2改成t1都可以,这里选择把t1转成utf8mb4。那怎么转字符集呢?

有的同学会说用alter table t1 charset utf8mb4;但这是错的,这只是改了表的默认字符集,即新的字段才会使用utf8mb4,已经存在的字段仍然是utf8。

只有用alter table t1 convert to charset utf8mb4;才是正确的。

但是还要注意一点,alter table 改字符集的操作是阻塞写的(用lock = node会报错)所以业务高峰时请不要操作,即使在业务低峰时期,大表的操作仍然建议使用pt-online-schema-change在线修改字符集。

mysql> alter table t1 convert to charset utf8mb4, lock=none;

ERROR 1846 (0A000): LOCK=NONE is not supported. Reason: Cannot change column type INPLACE. Try LOCK=SHARED.

现在再来查看执行计划,可以看到已经没问题了。

4. 注意点

(1)表字符集不同时,可能导致join的SQL使用不到索引,引起严重的性能问题;

(2)SQL上线前要做好SQL Review工作,尽量在和生产环境一样的环境下Review;

(3)改字符集的alter table操作会阻塞写,尽量在业务低峰操作,建议用pt-online-schema-change;

(4)表结构字符集要保持一致,发布时要做好审核工作;

(5)如果要大批量修改表的字符集,同样做好SQL的Review工作,关联的表的字符集一起做修改。

5. 问题讨论

最后问一个问题,假设现在t1和t2表的字符集还未修改,如果上面那个问题SQL换成如下(即把t2 left join t1换成t1 left join t2),还会出现索引失效问题吗?为什么?

select * from t1 join t2 on t1.code = t2.code where t1.name = 'dddd'

参考文章:InsideMySQL

mysql 各表charset不同_MySQL表字段字符集不同导致的索引失效问题相关推荐

  1. MySQL表字段字符集不同导致的索引失效问题

    MySQL表字段字符集不同导致的索引失效问题 转自:MySQL表字段字符集不同导致的索引失效问题 1. 概述 昨天在一位同学的MySQL机器上面发现了这样一个问题,MySQL两张表做left join ...

  2. mysql表 字段 说明_mysql表字段说明

    3.表字段说明: 3.1.数字: 3.1.1.整型: 说明: 整型如果指定了AUTO_INCREMENT,则列必须为PRIMARY KEY 或UNIQUE 索引:如果指定了UNSIGNED属性,则相应 ...

  3. mysql字符集和表字符集_设置数据库的字符集和设置表字段字符集的区别是什么?...

    对于oracle来说,只有数据库字符集这个说法,不存在什么表字符集和字段字符集.你说的这个是mysql的字符集,数据库字符集可以和表字符集不同,也可以和列字符集不同,也就是说,你的数据库字符集为utf ...

  4. mysql 大表查询慢_mysql大表查询慢怎么优化?

    mysql大表查询慢的优化方法:1.合理建立索引,通常查询利用到索引比不用索引更快:2.对关键字段建立水平分区,比如时间字段,若查询条件往往通过时间范围来进行查询,能提升不少性能:3.建立粗粒度数据表 ...

  5. mysql表字段长度限制_mysql表字段类型长度限制

    前置条件 本文使用的mysql版本均为5.7.24-log,innoDB引擎 表字段长度的限制 今天业务表需要添加字段,但是发现已经加不进去了,报以下错误... Row size too large. ...

  6. mysql数据库约束无符号,MySQL所支持的数据类型与表字段约束类型的学习教程

    MySQL 数据(字段)类型 在创建表的时候,要明确定义字段对应的数据类型.MySQL 主要的数据类型分为数值类型.字符串(文本)类型.时间日期类型和其他类型几类. 数值类型 数值类型说明: 补充说明 ...

  7. day38 mycql 初识概念,库(增删改查),表(增删改)以及表字段(增删改查),插入更新操作...

    在Navicat中把已经生成的表逆向成模型 数据库上,右键-逆向数据库到模型 ego笔记: 增删改查 文件夹(库)增create database day43 charset utf8;改alter ...

  8. mysql删除表编码字段_mysql 修改 添加 删除 表字段

    mysql 修改 添加 删除 表字段 添加表的字段 alter table 表名 add 字段名 字段的类型 例子: alter table table1 add transactor varchar ...

  9. mysql修改表的结构_MySQL修改表结构

    我们在修改表字段类型和约束条件的时候,如果表中的字段已经有值了,但是你修改的这个类型和字段里边的值不匹配是不允许修改的,就比如说你当初设置字段的时候,字段的值是允许存空值,并且字段里边已经存储空值了, ...

最新文章

  1. PHP变量在内存中的存储方式
  2. WPF快速指导5:验证
  3. python编程神器下载_Python编程神器 -程序员必备开发手册
  4. 音视频技术开发周刊 | 138
  5. asp.net利用RAR实现文件压缩解压缩(转)
  6. 力扣868. 二进制间距
  7. 不狂热不忧虑:观看波士顿动力机器人视频的正确姿势
  8. 国内博客搬家工具大全
  9. CMS-订单系统的分布式事务如何处理
  10. cv曲线面积的意义_浅谈圆锥曲线中的高级技巧
  11. 开心--开始--开发--开心
  12. 验证信用卡c语言,信用卡卡号验证算法
  13. 为啥外包喜欢php,为什么要面向对象?
  14. 画圆形图片的几种方式
  15. 计算机听音乐没有声音怎么回事,笔记本电脑听音乐没有声音怎么办
  16. android获取键盘状态,Android获取屏幕方向及键盘状态的小例子
  17. Android新浪微博实训报告,新浪微博产品简析
  18. Linux 系统 uos / deepin 系统安装过程中 最全常用命令及问题 总结
  19. CAD快速看图软件如何修改文字的样式
  20. 2k18 服务器不稳定,NBA2K18连接服务器出现错误代码怎么办_NBA2K18连接服务器出现错误代码解决办法_玩游戏网...

热门文章

  1. rndis ethernet gadget 驱动 安装方法
  2. Android 4.4.2 动态添加JNI库方法记录 (二 app应用层)
  3. S5 Linux信息显示与搜索文件命令
  4. 【教女朋友学网络系列3】之手把手教她明白交换机的基本原理
  5. 怎么求星期几的后几天C语言,计算任何一天是星期几的C语言源代码.
  6. 电脑工具栏怎么调整到下面_抖音怎么加字幕?如何制作短视频?
  7. 关于strlwr,strupr等函数在此作用域中尚未声明的问题
  8. 阿里云低延时直播RTS能力升级,让直播推流效果更佳
  9. 阿里云MongoDB,一直被模仿,从未被超越
  10. 监狱中的物联网用例:从尘土飞扬的监狱到智能监狱设施