优化案例

偏向于给开发的一篇数据库优化文章。

一 前言

在数据库表结构变更发布之前,我们会和开发沟通索引设计是否合理,发现部分开发同学对于索引设计还是有一些知识盲区。本文把常见的案例记录下来,做个分析,抛砖引玉。

区分度和过滤性

先看一段和开发同学日常sql review的对话:

上面的对话其实在工作中比较常见(同时也说明我们培训没有到位 T_T),这样的想法会导致开发忽略选择性比较低的字段,sql的执行计划使用 using where 匹配更多的数据行,结果执行耗时比较就,性能不理想。

大部分开发会接触到这样的开发规范:创建索引要选择区分度高的字段。他们会认为区分度低的字段不适合创建索引或者不适合添加到组合索引里面。但是这样的操作会导致很多慢查。举例来说,

select  * from  tab where a=1 and b=2;

场景1 符合 a=1 的记录数有 10w 条记录 ,b=2 有1000条记录。

如果只是创建 idx_a(a) ,sql请求通过索引 idx_a 访问 10w 条件记录,然后还要逐一匹配10w条记录中的status,找到符合 b=2 的记录。这个动作会导致慢查。

如果创建组合索引 idx_ab(a,b), sql请求通过索引 idx_ab 可以直接定位到1000条记录,无需额外的过滤,这样减少访问9900条记录的时间,提升查询速度。

场景2 符合a=1 的有100条记录,status=2 有10条记录。其实场景2 因为数据量比较少,直接访问100条记录和定位到10条记录的时间消耗相差不大,量变不足以引发质变,可以忽略了。

小结

1 创建索引的目的是sql请求通过索引尽可能快速地找到匹配where条件的行,减少不必要的回表,提高查询效率。

2 需要辩证地看待区分度比较低的字段在组合索引中的作用。在组合索引的情况下,我们不能只是单纯地看字段的区分度,而是要看符合条件的记录数是多少。符合条件的记录越少,性能越好。

索引的有序性

在优化业务sql的过程中,我们经常发现开发将 order by 的字段添加到组合索引里面,但是依然有 file sort 产生,导致慢查。这是为什么呢?

索引本身是有序的,之所以产生 file sort 说明组合索引中存在字段在索引中存储的顺序和order by 字段的顺序不一致,不是严格正相关导致 MySQL 根据结果重新排序。

order by 语句利用索引的有序性是有比较高要求的,组合索引中order by之前的字段必须是等值查询,不能是 in ,between,< ,> 等范围查询,explain 的type是 range 的sql 都会导致 order by 不能正常利用索引的有序性。

动手实践一下,初始化一张表x

create table x(id int not null auto_increment primary key, a int ,b int,key idx(a,b));insert into x(a,b) values(1,8),(1,6),(1,3),(2,1),(2,2),(2,4),(3,7),(3,9);

索引中存储的(a,b)顺序如下

mysql>  select * from x order  by a, b ; +----+------+------+| id | a    | b    |+----+------+------+|  3 |    1 |    3 ||  2 |    1 |    6 ||  1 |    1 |    8 ||  4 |    2 |    1 ||  5 |    2 |    2 ||  6 |    2 |    4 ||  7 |    3 |    7 ||  8 |    3 |    9 |+----+------+------+8 rows in set (0.00 sec)

对于组合索引 (a,b) 在where 条件中a=2使用等值查询,explain 的extra 字段中提示 using index ,并无额外的排序。

mysql> select * from x where a=2 order  by b;+----+------+------+| id | a    | b    |+----+------+------+|  4 |    2 |    1 ||  5 |    2 |    2 ||  6 |    2 |    4 |+----+------+------+3 rows in set (0.00 sec)

mysql> desc select * from x where a=2 order  by b \G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: x   partitions: NULL         type: refpossible_keys: idx          key: idx      key_len: 5          ref: const         rows: 3     filtered: 100.00        Extra: Using index1 row in set, 1 warning (0.00 sec)

对于组合索引 (a,b) 在where 条件中a使用范围查询,执行计划中出现Using filesort 排序。说明 order by b 并未利用索引的有序性,进行了额外的排序。

mysql> select * from x where a>=1 and a<3 order  by b;+----+------+------+| id | a    | b    |+----+------+------+|  4 |    2 |    1 ||  5 |    2 |    2 ||  3 |    1 |    3 ||  6 |    2 |    4 ||  2 |    1 |    6 ||  1 |    1 |    8 |+----+------+------+6 rows in set (0.00 sec)

mysql> desc select * from x where a>=1 and a<3 order  by b \G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: x   partitions: NULL         type: rangepossible_keys: idx          key: idx      key_len: 5          ref: NULL         rows: 6     filtered: 100.00        Extra: Using where; Using index; Using filesort1 row in set, 1 warning (0.01 sec)

数据ab在索引中的顺序和实际访问的结果顺序不一致,需要额外的排序就产生了file sort 。

(a,b)字段在索引中存储的顺序如下图,明显和上面的查询条件的结果顺序不一致,就导致sql执行计划出现额外的排序,数据量比较大的情况(比如5000以上)下就出现慢查。

小结

本文总结两种出现频率比较高的场景。希望开发同学看完本文之后,能设计出更合理的索引。

推荐阅读

再说 order by 优化

order by 原理以及优化

mysql一张表能存多少条数据不影响性能_MySQL|优化案例两则相关推荐

  1. MySQL中用存储过程实现银行转账并且在另一张表中添加一条数据

    SQL文件: /*Navicat Premium Data TransferSource Server : hellowordSource Server Type : MySQLSource Serv ...

  2. mysql每秒最多能插入多少条数据 ? 死磕性能压测

    2019独角兽企业重金招聘Python工程师标准>>> 前段时间搞优化,最后瓶颈发现都在数据库单点上. 问DBA,给我的写入答案是在1W(机械硬盘)左右. 联想起前几天infoQ上一 ...

  3. mysql某张表删除慢_Mysql某个表有近千万数据,CRUD比较慢,如何优化?

    我是[会点代码的大叔],每天为你分享程序员干货,关注并私信我数字"1",送你一份程序员大礼包. MySQL 数据库某张表近千万的数据,CRUD比较慢,如何优化? 说实话,这个数据量 ...

  4. 怎么向表结构是自增长的表中插入一条数据 SQLCODE=-798, SQLSTATE=428C9, SQLERRMC=ID

    最近碰到向一张表中插入一条数据,可怎么样都是失败的,报错: SQLCODE=-798, SQLSTATE=428C9, SQLERRMC=ID 这个错的意思是不能向自增长的表中插入数据. 那怎么办呢? ...

  5. 关于mysql一张表到底能存多少数据?

    前言 程序员平时和mysql打交道一定不少,可以说每天都有接触到,但是mysql一张表到底能存多少数据呢?计算根据是什么呢?接下来咱们逐一探讨 知识准备 数据页 在操作系统中,我们知道为了跟磁盘交互, ...

  6. mysql一张表100亿条数据_一个表有100亿条记录,如何优化

    我们的数据库还在设计阶段.我们预计数据量将会很大,一年的时间里,一张表,就会产生100亿条数据,表结构,如下id,userid,createddate,等等正常情况下,100亿条记录如果都存在一个表里 ...

  7. linux打开mysql某张表_Linux——MySQL多表连接

    本章内容会将知识点结合例题进行介绍,涉及到相关数据库表结构如下: 交叉连接:笛卡尔积,可以理解为一张表中的每条记录都会对应另一张表的根据连接条件匹配到 的记录,注意是循环匹配. 交叉连接分为一般交叉连 ...

  8. mysql数据库中,查询一个表的下一条数据减上一条数据的值的写法

    mysql数据库中,查询一个表的下一条数据减上一条数据的值的写法: select a.nodeId,a.cpuCharge-b.cpuCharge cpuCharge, a.chargeTime fr ...

  9. mysql 表的第2条到4条记录,mysql怎么查询第2到4条数据

    mysql怎么查询第2到4条数据 在mysql中可以通过"LIMIT"关键字来查询第2到4条数据,具体语句为"SELECT * FROM 数据表名 LIMIT 1,3;& ...

  10. 创建商品表中插入一条数据/图书表中新增一条记录/学生表中,要求查询姓张,并且年龄在18到25岁之间的学生/查询article文章表

    在以上创建的商品表中插入一条数据:名称为"学生书包".价格18.91.库存101.描述为空 在图书表中新增一条记录:Java核心技术.作者"Cay S. Horstman ...

最新文章

  1. 每日一皮:高级开发员 VS 菜鸟开发员
  2. 体感Kinect手势识别开发基本原理
  3. 写段QTP脚本与大家一起分享
  4. Latex与VSCode环境搭建问题解决
  5. 《阿里巴巴Android开发手册》正式发布,献给移动开发者的新年礼物
  6. CCF202109-2 非零段划分
  7. 戴尔t140服务器价格型号,戴尔_PowerEdge T140塔式服务器_企业服务器_网络存储服务器 | Dell 中国大陆...
  8. Windows API 学习记录1
  9. 关于ORM的一些外文资料
  10. 删除链表倒数第N个节点
  11. python更新包列表出错_python – 完整更新pip包时出错
  12. 做微商不推广,也能赚钱?
  13. html 编辑器 拖动,可视化拖拽页面编辑器 一
  14. Java如何避免空指针异常?
  15. b站pink老师JavaScript的PC端网页特效 案例代码——引用animate.js案例
  16. C语言完整知识体系总结
  17. Android RSA加密解密
  18. 简洁、快速的JavaScript框架/库:jQuery
  19. iPhone6p后摄像头抖动的问题
  20. USBHID-BUS Hound能抓到数据但上位机读不到数据

热门文章

  1. 使用delphi 10.2 开发linux 上的Daemon
  2. Java——泛型(最易懂的方式讲解泛型)
  3. LockSupport类中的park()和unpark()
  4. Html5新特性 canvas画板画直线和等比缩放居中裁剪图片
  5. oracle中使用impdp数据泵导入数据提示“ORA-31684:对象类型已经存在”错误的解决......
  6. vue源码分析系列之响应式数据(三)
  7. Python Django 之 jQuery
  8. linux下用C计算某一个目录总大小
  9. 中国工业机器人市场正在迎来爆发式增长
  10. python模拟ssh登录