效率提高N倍的19条MySQL优化秘籍

一、EXPLAIN

做MySQL优化,我们要善用 EXPLAIN 查看SQL执行计划。

下面来个简单的示例,标注(1,2,3,4,5)我们要重点关注的数据

  • type列,连接类型。一个好的sql语句至少要达到range级别。杜绝出现all级别
  • key列,使用到的索引名。如果没有选择索引,值是NULL。可以采取强制索引方
  • key_len列,索引长度
  • rows列,扫描行数。该值是个预估值
  • extra列,详细说明。注意常见的不太友好的值有:Using filesort, Using temporary

二、SQL语句中IN包含的值不应过多

MySQL对于IN做了相应的优化,即将IN中的常量全部存储在一个数组里面,而且这个数组是排好序的。但是如果数值较多,产生的消耗也是比较大的。再例如:select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了;再或者使用连接来替换。

三、SELECT语句务必指明字段名称

SELECT *增加很多不必要的消耗(cpu、io、内存、网络带宽);增加了使用覆盖索引的可能性;当表结构发生改变时,前断也需要更新。所以要求直接在select后面接上字段名。

四、当只需要一条数据的时候,使用limit 1

这是为了使EXPLAIN中type列达到const类型

五、如果排序字段没有用到索引,就尽量少排序

六、如果限制条件中其他字段没有索引,尽量少用or

or两边的字段中,如果有一个不是索引字段,而其他条件也不是索引字段,会造成该查询不走索引的情况。很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果。

七、尽量用union all代替union

union和union all的差异主要是前者需要将结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的CPU运算,加大资源消耗及延迟。当然,union all的前提条件是两个结果集没有重复数据。

八、不使用ORDER BY RAND()

select id from `dynamic` order by rand() limit 1000;

上面的sql语句,可优化为

select id from `dynamic` t1 join (select rand() * (select max(id) from `dynamic`) as nid) t2 on t1.id > t2.nidlimit 1000;

九、区分in和exists, not in和not exists

select * from 表A where id in (select id from 表B)

上面sql语句相当于

select * from 表A where exists(select * from 表B where 表B.id=表A.id)

区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询。所以IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。

关于not in和not exists,推荐使用not exists,不仅仅是效率问题,not in可能存在逻辑问题。如何高效的写出一个替代not exists的sql语句?

原sql语句

select colname … from A表 where a.id not in (select b.id from B表)

高效的sql语句

select colname … from A表 Left join B表 on where a.id = b.id where b.id is null

取出的结果集如下图表示,A表不在B表中的数据

十、使用合理的分页方式以提高分页的效率


select id,name from product limit 866613, 20

使用上述sql语句做分页的时候,可能有人会发现,随着表数据量的增加,直接使用limit分页查询会越来越慢。

优化的方法如下:可以取前一页的最大行数的id,然后根据这个最大的id来限制下一页的起点。比如此列中,上一页最大的id是866612。sql可以采用如下的写法:

select id,name from product where id> 866612 limit 20

十一、分段查询

在一些用户选择页面中,可能一些用户选择的时间范围过大,造成查询缓慢。主要的原因是扫描行数过多。这个时候可以通过程序,分段进行查询,循环遍历,将结果合并处理进行展示。

如下图这个sql语句,扫描的行数成百万级以上的时候就可以使用分段查询

十二、避免在 where 子句中对字段进行 null 值判断

对于null的判断会导致引擎放弃使用索引而进行全表扫描。

十三、不建议使用%前缀模糊查询

例如LIKE “%name”或者LIKE “%name%”,这种查询会导致索引失效而进行全表扫描。但是可以使用LIKE “name%”。
那如何查询%name%?
如下图所示,虽然给secret字段添加了索引,但在explain结果果并没有使用

那么如何解决这个问题呢,答案:使用全文索引

在我们查询中经常会用到select id,fnum,fdst from dynamic_201606 where user_name like ‘%zhangsan%’; 。这样的语句,普通索引是无法满足查询需求的。庆幸的是在MySQL中,有全文索引来帮助我们。

创建全文索引的sql语法是:

ALTER TABLE `dynamic_201606` ADD FULLTEXT INDEX `idx_user_name` (`user_name`);

使用全文索引的sql语句是:

select id,fnum,fdst from dynamic_201606 where match(user_name) against('zhangsan' in boolean mode);

注意:在需要创建全文索引之前,请联系DBA确定能否创建。同时需要注意的是查询语句的写法与普通索引的区别

十四、避免在where子句中对字段进行表达式操作


比如

select user_id,user_project from user_base where age*2=36;

中对字段就行了算术运算,这会造成引擎放弃使用索引,建议改成

select user_id,user_project from user_base where age=36/2;

十五、避免隐式类型转换

where 子句中出现 column 字段的类型和传入的参数类型不一致的时候发生的类型转换,建议先确定where中的参数类型

十六、对于联合索引来说,要遵守最左前缀法则

举列来说索引含有字段id,name,school,可以直接用id字段,也可以id,name这样的顺序,但是name;school都无法使用这个索引。所以在创建联合索引的时候一定要注意索引字段顺序,常用的查询字段放在最前面

十七、必要时可以使用force index来强制查询走某个索引

有的时候MySQL优化器采取它认为合适的索引来检索sql语句,但是可能它所采用的索引并不是我们想要的。这时就可以采用forceindex来强制优化器使用我们制定的索引。

十八、注意范围查询语句

对于联合索引来说,如果存在范围查询,比如between,>,<等条件时,会造成后面的索引字段失效。

十九、关于JOIN优化

LEFT JOIN A表为驱动表

INNER JOIN MySQL会自动找出那个数据少的表作用驱动表
RIGHT JOIN B表为驱动表
注意:MySQL中没有full join,可以用以下方式来解决
select * from A left join B on B.name = A.namewhere B.name is nullunion allselect * from B;
尽量使用inner join,避免left join
参与联合查询的表至少为2张表,一般都存在大小之分。如果连接方式是inner join,在没有其他过滤条件的情况下MySQL会自动选择小表作为驱动表,但是left join在驱动表的选择上遵循的是左边驱动右边的原则,即left join左边的表名为驱动表。
合理利用索引
被驱动表的索引字段作为on的限制字段。
利用小表去驱动大表

从原理图能够直观的看出如果能够减少驱动表的话,减少嵌套循环中的循环次数,以减少 IO总量及CPU运算的次数。

巧用STRAIGHT_JOIN

inner join是由mysql选择驱动表,但是有些特殊情况需要选择另个表作为驱动表,比如有group by、order by等「Using filesort」、「Using temporary」时。STRAIGHT_JOIN来强制连接顺序,在STRAIGHT_JOIN左边的表名就是驱动表,右边则是被驱动表。在使用STRAIGHT_JOIN有个前提条件是该查询是内连接,也就是inner join。其他链接不推荐使用STRAIGHT_JOIN,否则可能造成查询结果不准确。

出处:https://zhuanlan.zhihu.com/p/49888088

编辑:尹文敏

Image placeholder
1nnovator
未设置
  42人点赞

没有讨论,发表一下自己的看法吧

推荐文章
一通骚操作,我把SQL执行效率提高了10000000倍!

场景我用的数据库是mysql5.6,下面简单的介绍下场景课程表:create table Course(c_id int PRIMARY KEY,name varchar(10))数据100条学生表:

MySQL优化之覆盖索引的使用

查看测试表结构:mysql>showcreatetableim_message\G ***************************1.row**************************

使用这些idea插件让开发效率提高5倍

idea有很多非常好用的插件,用好了这些插件能够极大的提高开发效率插件用的好,bug就追不上了我😆 0.idea插件如何安装打开idea的设置页面,选择Plugins选项即可搜索和安装插件1.JReb

TPC-C解析系列03_TPC-C基准测试之SQL优化

TPC-C是一个非常严苛的基准测试模型,考验的是一个完备的关系数据库系统全链路的能力。这也是为什么在TPC-C的榜单前列,出现的永远只是大家熟知的那几家在业界有着几十年积累、从关系数据库理论开始发展就

SQL优化案例-定位系统中大量的rollback(十八)

系统中logfilesync比较严重,查看存储都没有问题,logfileparallelwrite很低,时间分布直方图也没问题数据库中提交和回滚操作比较频繁,每秒1000多次,rollback占比1/

【Golang+MySQL】记一次 MySQL 数据库迁移(一)

【Golang+mysql】记一次mysql数据库迁移(一)文章地址:https://github.com/stayfoo/stayfoo-hub一、准备目标: 腾讯云CVM自建mysql数据迁移到腾

MySQL 性能优化:8 种常见 SQL 错误用法!

1、LIMIT语句分页查询是最常用的场景之一,但也通常也是最容易出问题的地方。比如对于下面简单的语句,一般DBA想到的办法是在type,name,create_time字段上加组合索引。这样条件排序都

秘籍在手,训练不愁!特斯拉AI负责人Karpathy的超全神经网络训练套路

大数据文摘出品编译:周素云、宋欣仪、熊琰、ZoeY、顾晨波训练神经网络到底有诀窍和套路吗?AndrejKarpathy认为,还的确有。这位特斯拉的人工智能研究负责人、李飞飞的斯坦福高徒刚刚难得更新了博

揭秘青云QingCloud第二代云主机性能提升4倍的背后

前不久,青云QingCloud正式推出第二代企业型云主机,其搭载第二代英特尔至强可扩展处理器,采用独享CPU模式,可提供更高更稳定的计算性能,并针对人工智能工作负载进行优化,性能提升400%,满足企业

我在职场第一次薪资翻倍的经历!

一个有所追求的人。1写在前面我将用系列文章,回顾十年程序生涯,一方面是对职场生涯的阶段性总结,另一方面希望这些经历,对大家往后职场生涯有所启发。我很庆幸一路走来皆是自己的选择,虽然也走了不少弯路,但那

MySQL 优化笔记

优化方向 SQL优化 sql优化分析 索引优化 优化数据库对象 优化表的数据类型 表拆分(水平、垂直) 反范式 使用中间表 优化mysqlserver mysql内存管理优化 log机制及优化

MySQL 优化笔记

优化方向 SQL优化 sql优化分析 索引优化 优化数据库对象 优化表的数据类型 表拆分(水平、垂直) 反范式 使用中间表 优化mysqlserver mysql内存管理优化 log机制及优化

MySQL 百万级数据量分页查询方法及其优化

作者|大神养成记原文|  http://t.cn/RnvCJnm方法1:直接使用数据库提供的SQL语句语句样式: MySQL中,可用如下方法:SELECT*FROM表名称LIMITM,N适应场景: 适

MySQL 亿级数据数据库优化方案测试-银行交易流水记录的查询

作者:逸宸a链接:https://www.jianshu.com/p/cbdef47fb837对MySQL的性能和亿级数据的处理方法思考,以及分库分表到底该如何做,在什么场景比较合适?比如银行交易流水

Oracle/云MySQL/MsSQL“大迁移”真相及最优方案

最近一段时间碰到一些数据迁移的项目,如:Oracle迁移到MySQL,MsSQL迁移到MySQL,云MySQL迁移到本地MySQL。对于这方面做了系统的整理。包括:迁移方案的选择、如何跳出迁移遇到的坑

一条SQL语句在MySQL中如何执行的

前两天发了一条SQL慢的原因有哪些,在那篇文章我没有说到优化器之类的,我觉得如果配合一条SQL是如何执行的,会更好,所以特地找了一篇。来源:JavaGuide  |作者:木木匠本篇文章会分析一个sql

mysql 进行update时,要更新的字段中有单引号或者双引号导致不能批量生成sql的问题

前言将数据从一张表迁移到另外一张表的过程中,通过mysql的concat方法批量生成sql时遇到了一个问题,即进行UPDATE更新操作时如果原表中的字段中包含单引号'或者双引号",那么就会生成不正确的

2019年8月数据库流行度排行:双星闪耀 MySQL 成月度最大赢家

炎炎夏日,DB-Engines的8月榜单已经发布,本月积分MySQL获得了最显著的增长,较上月增加了24分,Oracle获得了18分的增长,Oracle公司的两个王牌产品,闪耀8月。以下是前10名的榜

2019年9月数据库流行度排行:MySQL 强劲增长完成深 V 反转

导读:DB-Engines的2019年9月数据库流行度排行榜已经发布,本月最耀眼的明星是MySQL,分值大幅增长25.39分,较年初已经上升了125分,增幅达10%,完成了一次深V反转。相较之下,Or

这些linux技巧大大提高你的工作效率

前言linux中的一些小技巧可以大大提高你的工作效率,本文就细数那些提高效率或者简单却有效的linux技巧。命令编辑及光标移动这里有很多快捷键可以帮我们修正自己的命令。接下来使用光标二字代替光标的位置

老焦专栏 | 用 RACI 模式梳理业务流程,提高业务发布的效率

转载本文需注明出处:微信公众号EAWorld,违者必究。最近经常在不同场合说,技术发展已经进入深水区。IT技术发展已经越来越成熟了,尤其在金融行业,以前是解决从无到有的问题,现在该有的系统都有了,是解

如何利用科技提高效率,降低成本

以前,企业用数据库来存储客户信息,这些信息必须谨慎保存,并且需要实时手动更新。今天,有许多自动化CRM工具在被设计时考虑了各个行业不同的需求。过去,无论企业规模大小,都必须向客户开具纸质发票,并等待数

Java没有创新了吗?Java 13提供可提高生产率和效率的功能

在其CodeOne会议上,Oracle解释了JavaSE13正式发布后Java的快速发布周期如何带来创新。在过去的二十多年中,Java编程语言新版本的开发速度相对较慢,仅每隔几年就会进行重大更新。甲骨

MongoDB初学者最常用的10个命令

1.登录mongodb 以下命令可以用于登录mongodb数据库,但是需要保证用户你声明的数据库中存在对应的用户和密码 mongo--host--port-u-p--authenticationDat

程序员常用的15 种开发者工具推荐

  程序员常用的15种开发者工具引荐:Java线上诊断工具Arthas、IDE插件CloudToolkit、混沌实验注入工具ChaosBlade、Java代码规约扫描插件、应用实时监控工具ARMS、静