一文带你掌握MySQL查询优化技能
查询优化本就不是一蹴而就的,需要学会使用对应的工具、借鉴别人的经验来对SQL进行优化,并且提升自己。
分享一套博主觉得讲的很详细很实用的MySQL教程给大家,可直接点击观看!
https://www.bilibili.com/video/BV1fx411X7BD
先来巩固一下索引的优点,检索数据快、查询稳定、存储具有顺序性避免服务器建立临时表、将随机的I/O变为有序的I/O。
但索引一旦创建的不规范就会造成以下问题,占用额外空间,浪费内存,降低数据的增、删、改性能。
所以只有在理解索引数据结构的基础上才能创建出高效的索引。
**本文所有操作均在MySQL8.0.12**
一、创建索引规范
在学习索引优化之前,需要对创建索引的规范有一定的了解,此规范来自于阿里巴巴开发手册。
- 主键索引:pk_column_column
- 唯一索引:uk_column_column
- 普通索引:idx_column_column
二、索引失效原因
创建索引需知道在什么情况下索引会失效,只有了解索引失效的原因,在创建索引时才不会出现一些已知错误。
1.带头大哥不能死
这局经典的语句就是涵盖创建索引时一定要符合最左侧原则。
例如表结构为u_id,u_name,u_age,u_sex,u_phone,u_time
创建索引为idx_user_name_age_sex。
查询条件必须带上u_name这一列。
2.不在索引列上做任何操作
不在索引列上做任何计算、函数、自动或者手动的类型转换,否则会进行全表扫描。简而言之不要在索引列上做任何操作。
3.俩边类型不等
例如建立了索引idx_user_name,name字段类型为varchar
在查询时使用where name = kaka,这样的查询方式会直接造成索引失效。
正确的用法为where name = “kaka”。
4.不适当的like查询会导致索引失效
创建索引为idx_user_name
执行语句为select * from user where name like “kaka%”;可以命中索引。
执行语句为select name from user where name like “%kaka”;可以使用到索引(仅在8.0以上版本)。
执行语句为select * from user where name like ‘’%kaka";会直接导致索引失效
5.范围条件之后的索引会失效
创建索引为idx_user_name_age_sex
执行语句select * from user where name = ‘kaka’ and age > 11 and sex = 1;
上面这条sql语句只会命中name和age索引,sex索引会失效。
复合索引失效需要查看key_len的长度即可。
总结:%在后边会命令索引,当使用了覆盖索引时任何查询方式都可命中索引。
以上就是关于索引失效会出现的原因总结,在很多文章中没有标注MySQL版本,所以你有可能会看到is null 、or索引会失效的结论。
三、SQL优化杀手锏之Explain
在写完SQL语句之后必须要做的一件事情就是使用Explain进行SQL语句检测,看是否命中索引。
下图就是使用explain输出格式,接下来将会对输出格式进行简单的解释。

1.id
这列就是查询的编号,如果查询语句中没有子查询或者联合查询这个标识就一直是1。
如存在子查询或者联合查询这个编号会自增。
2.select_type
最常见的类型就是SIMPLE和PRIMARY,此列知道就行了。
3.table
理解为表名即可
4.**type
此列是在优化SQL语句时最需要关注的列之一,此列显示了查询使用了何种类型。
以下排序从最优到最差。
- system:表内只有一行数据
- const:最多只会有一条记录匹配,常用于主键或者唯一索引为条件查询
- eq_ref:当连接使用的索引为主键和唯一时会出现
- ref:使用普通索引=或<=> 运算符进行比较将会出现
- fulltext:使用全文索引
- ref_or_null:跟ref类型类似,只是增加了null值的判断,实际用的不多。语句为where name = ‘kaka’ and name is null,name为普通索引。
- index_merge:查询语句使用了俩个以上的索引,常见在使用and、or会出现,官方文档将此类型放在ref_or_null之后,但是在很多的情况下由于读取索引过多性能有可能还不如range
- unique_subquery:用于where中的in查询,完全替换子查询,效率更高。语句为value IN (SELECT primary_key FROM single_table WHERE some_expr)
- index_subquery:子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或唯一索引
- range:索引范围查询,常见于使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()或者like等运算符的查询中。
- index:索引全表扫描,把索引从头到尾扫一遍
- all:全表扫描,性能最差。
5.possible_keys
此列显示的可能会使用到的索引
6.**key
优化器从possible_keys中命中的索引
7.key_len
查询用到的索引长度(字节数),key_len只计算where条件用到的索引长度,而排序和分组就算用到了索引,也不会计算到key_len中。
8.ref
如果是使用的常数等值查询,这里会显示const。
如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段。
如果是条件使用了表达式或者函数,或者条件列发生了内部隐式转换,这里可能显示为func。
9.**rows
这是mysql估算的需要扫描的行数(不是精确值)。
这个值非常直观显示 SQL 的效率好坏, 原则上 rows 越少越好。
10.filtered
此列表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意是百分比,不是具体记录数
11.**extra
在大多数情况下会出现以下几种情况。
- Using index:使用了覆盖索引,查询列都为索引字段
- Using where:使用了where语句
- Using temporary :查询结果进行排序的时候使用了一张临时表
- Using filesort :对数据使用一个外部的索引排序
- Using index condition:使用了索引下推,关于索引下推可以查看之前文章MySQL索引一文
12.总结
以上就是关于Explain所有列的说明,在平时开发的过程中,一般只会关注type、key、rows、extra这四列。
- type优化目标至少达到range级别,要求是ref级别,如果可以consts最好。
- key是查询使用到的索引,如果此列为空,要么未建立索引,要么索引失效。
- rows是这条SQL语句扫描的行数,越少越好。
- extra:此列为扩展列,如果出现临时表、文件排序则需要优化。
四、SQL优化杀手锏之慢查询
上文说到了可以直接使用explain来分析自己的SQL语句是否合理,接下来再聊一个点那就是慢查询。
查看慢查询是否打开

查看是否记录没有使用索引的SQL语句

开启慢查询、开启记录没有使用到索引的SQL语句
set global log_queries_not_using_idnexes=‘on’;
set global log_queries_not_using_indexes=‘on’;

查询以上俩个配置是否打开

设置慢查询时间,这个时间由自己把控,一般1s即可set globle long_query_time=1;
如果查看这个时间没有变,则关于客户端在重新连接一次即可。

查看慢查询存储位置

然后随便执行一条不执行索引的语句即可在这个日志中查看到此语句

上图中一般需要主要观察的是Query_time、SQL语句内容。
以上就是关于如何使用慢查询来查看项目中出现问题的SQL语句。
五、优化大法
此处跟大家聊一些常用的SQL语句优化方案,以上的俩个工具要好好的利用,辅助我们进行打怪。
- 禁止使用select *,需要什么字段查询什么字段
- where字段设置索引
- group by、order by字段设置索引
- 舍弃offset,limit分页,使用延迟关联来实现分页(数据量不大时可不用)
- 写分页时当count为0时,直接返回避免执行分页语句
- 利用覆盖索引进行查询避免回表
- 建立复合索引时区分度最高的放在最左侧
- 统计数据行数只用count(*),别整的花里胡哨的
- 关于in和exist,如果查询的俩个表大小一致则性能差别可忽略,如果子查询表大用exist,否则使用in
- 查询一行数据时加上limit 1
- 选择合理的数据类型,在满足条件下数据类型越小越好
- 联合查询join最多三个表,并且需要join的字段数据类型保持一致
- in操作能避免尽量避免,无法避免的情况下in元素控制在1000以内
- 数据更新频繁,区分度不高的列不适合建立索引
- explain中的type至少要达到range,要求为ref
- 联合索引满足最左侧原则
一文带你掌握MySQL查询优化技能的更多相关文章
- JDBC、ORM、JPA、Spring Data JPA,傻傻分不清楚?一文带你厘清个中曲直,给你个选择SpringDataJPA的理由!
序言 Spring Data JPA作为Spring Data中对于关系型数据库支持的一种框架技术,属于ORM的一种,通过得当的使用,可以大大简化开发过程中对于数据操作的复杂度. 本文档隶属于< ...
- Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析
Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析 Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析1 存 ...
- Mysql查询优化器
Mysql查询优化器 本文的目的主要是通过告诉大家,查询优化器为我们做了那些工作,我们怎么做,才能使查询优化器对我们的sql进行优化,以及启示我们sql语句怎么写,才能更有效率.那么到底mysql到底 ...
- Mysql查询优化器浅析
--Mysql查询优化器浅析 -----------------------------2014/06/11 1 定义 Mysql查询优化器的工作是为查询语句选择合适的执行路径.查询优化器的代码 ...
- MySQL查询优化(转)
在分析性能欠佳的查询时,应考虑: 1) 应用程序是否正获取超过需要的数据,即访问了过多的行或列. 2) Mysql服务器是否分析了超过需要的行. 如果发现访问的数据行数很大,而生成的结果中数据行很少, ...
- MYSQL查询优化:使用索引
索引是提高查询速度的最重要的工具.当然还有其它的一些技术可供使用,但是一 般来说引起最大性能差异的都是索引的正确使用.在MySQL邮件列表中,人们经常询问那些让查询运行得更快的方法.在大多数情况下,我 ...
- MySQL 查询优化之 Multi-Range Read
MySQL 查询优化之 Multi-Range Read MRR的工作原理 MRR开启与关闭 使用MRR示例 参考文档 在存储引擎中未缓存的大表,使用辅助索引的range scan检索数据, 可能会导 ...
- MySQL 查询优化之 Index Merge
MySQL 查询优化之 Index Merge Index Merge Intersection 访问算法 Index Merge Union 访问算法 Index Merge Sort-Union ...
- 一文带你了解elasticsearch
一文带你了解elasticsearch cxf2102100人评论160人阅读2019-07-02 21:31:36 elasticsearch es基本概念 es术语介绍 文档Document ...
随机推荐
- RabbitMQ(二) Java使用RabbitMQ
2-1 RabbitMQ 生产者消息发送 创建 Maven 项目 Send 加入依赖 <dependency> <groupId>com.rabbitmq</groupI ...
- SSRF攻击原理
目录 什么是SSRF 原理 防护 什么是SSRF 一个对外的Web接口,改接口能让用户控制curl命令,去访问别的web服务. 简图如下 想象一下当用户请求的baidu.com/x.php?image ...
- LeetCode-重建二叉树(前序遍历+中序遍历)
重建二叉树 LeetCode-105 首次需要知道前序遍历和中序遍历的性质. 解题思路如下:首先使用前序比遍历找到根节点,然后使用中序遍历找到左右子树的范围,再分别对左右子树实施递归重建. 本题的难点 ...
- POJ-2195(最小费用最大流+MCMF算法)
Going Home POJ-2195 这题使用的是最小费用流的模板. 建模的时候我的方法出现错误,导致出现WA,根据网上的建图方法没错. 这里的建图方法是每次到相邻点的最大容量为INF,而花费为1, ...
- Java 语言基础 02
语言基础·二级 顺序结构语句 * A:什么是流程控制语句 * 流程控制语句:可以控制程序的执行流程. * B:流程控制语句的分类 * 顺序结构 * 选择结构 * 循环结构 * ...
- MySQL 40题练习题和答案
2.查询"生物"课程比"物理"课程成绩高的所有学生的学号: 思路: 获取所有有生物课程的人(学号,成绩) - 临时表 获取所有有物理课程的人(学号, ...
- 漏洞复现-CVE-2018-15473-ssh用户枚举漏洞
0x00 实验环境 攻击机:Win 10 0x01 影响版本 OpenSSH 7.7前存在一个用户名枚举漏洞,通过该漏洞,攻击者可以判断某个用户名是否存在于目标主机 0x02 漏洞复现 针 ...
- [DP浅析]线性DP初步 - 2 - 单调队列优化
目录 #0.0 前置知识 #1.0 简单介绍 #1.1 本质 & 适用范围 #1.2 适用方程 & 条件 #2.0 例题讲解 #2.1 P3572 [POI2014]PTA-Littl ...
- addEventListener的第三个参数详解
示例代码 element.addEventListener("mousedown", func, { passive: true }); element.addEventList ...
- Python中面向对象的概念
1.语言的分类 1)面向机器 抽象成机器指令,机器容易理解.代表:汇编语言. 2)面向过程 做一件事,排除步骤,第一步做什么,第二步做什么,如果出现A问题,做什么处理,出现b问题,做什么处理.问题规模 ...