MySQ慢查询+索引与执行计划

一.慢查询

1.什么是慢查询?

慢查询日志,顾名思义也就是查询慢的日志(记录数据库事件, 协助用户分析和解决问题),是指mysql记录所有执行超过long_query_time参数设定的时间阀值得SQL语句得日志。该日志可以为SQL语句的优化带来很好的帮助。默认情况下,慢查询日志是关闭的,要使用慢查询日志的功能,首先要开启。

2.慢查询配置

MySQ慢查询+索引与执行计划_第1张图片

MySQ慢查询+索引与执行计划_第2张图片

查看慢查询日志
MySQ慢查询+索引与执行计划_第3张图片
查询日志中,各行内容代表的意思
MySQ慢查询+索引与执行计划_第4张图片

二.索引

1.什么是索引?

MySQL官方的定义为:索引是帮助MySQL获取数据的数据结构。可以看出索引是数据结构。

2.索引数据结构

InnoDB只显示支持的B-Tree
MySQ慢查询+索引与执行计划_第5张图片

数据结构中比B树的B+树存在更快的查找树,MySQL为什么没有采用呢?因为索引文件是储存在磁盘中的,索引太大那么磁盘IO无法一次读入进,二叉查找树虽然快,但是比较"高",需要读很多次,这样磁盘IO的速度大大高于二叉查找树快的速度。所以采用B树,这种树设计的"矮",IO次数最少。也就加快了数据库的速度。



B+树只有叶子节点才存真实数据
MySQ慢查询+索引与执行计划_第6张图片



B树和B+树的区别可以参考:
https://www.cnblogs.com/windy-xmwh/p/9298509.html
B树
MySQ慢查询+索引与执行计划_第7张图片
B+树
MySQ慢查询+索引与执行计划_第8张图片

B树和B+树最大区别在于B树每个节点储存key和value,但是B+树每个节点只存key,只有叶子节点存的是整个树的value,然后用指针串成链表,B+树的优势在于,索引节点数据紧凑,并且遍历整个树快,只需要从叶子节点遍历即可,但是B树也有其优点,就是如果查找的数离根节点很近,那么就会十分快。

MySQ慢查询+索引与执行计划_第9张图片




3.适合建立索引的情况?

索引并不是越多越好,第一,需要维护这个索引表,表太多增大储存压力。第二,每次的更新数据都是需要重新维护索引表,会带来成本。所以以下情况下的列,适合建立索引,但一般一张表不要超过5个索引。

  • 1.某一列相对唯一(比如重名的很少,但是重性别的很多)。
  • 2.经常用来做读的列。
  • 3.经常用来where查询的列,或者join on需要的的列。

4.索引分类

  • 普通索引:即一个索引只包含单个列,一个表可以有多个单列索引。
  • 唯一索引:UNIQUE索引列的值必须唯一,但允许有空值。
  • 复合索引(联合索引):即一个索引包含多个列。
  • 聚集索引:聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。一个表只能有一个聚集索引,因为一个表的物理顺序只有一种情况,所以,对应的聚集索引只能有一个。如果某索引不是聚集索引,则表中的行物理顺序与索引顺序不匹配,与非聚集索引相同,聚集索引有着更快的检索速度。
  • 非聚集索引:非聚集索引是一种索引,该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同。


5.联合(复合)索引

联合索引又叫复合索引,即一个覆盖表中两列或者以上的索引,重点是左匹配问题,例如联合索引为col1,col2,col3,   SELECT * FROM table WHERE col1=? AND col2=? AND col3=? 限定条件必须符合左匹配此联合索引才可以起作用。比如col1,col2或者col1,col2,col3 但是col2,col3则不行。
由于联合索引的数据底层,是最左边的col1列作为索引,其余列都分布在叶子节点中。
MySQ慢查询+索引与执行计划_第10张图片





三.执行计划

1.执行计划是什么?

使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句是表结构的性能瓶颈。

语法:Explain+SQL语句
MySQ慢查询+索引与执行计划_第11张图片



2.执行计划的作用

去清楚以下内容,方便对数据的执行优化

  • 表的读取顺序
  • 数据读取操作的操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询

在这里插入图片描述

id:select子句的操作顺序

  • 如果id值相同,子查询从上往下按顺序执行。
  • 如果id值不同,子查询id值越大的优先级越高。
  • 如果id存在相同的,但也有不同的。id相同的会被分一组,从上往下执行。其余依旧保证按id大小优先级进行执行,越大越先。

select_type:主要用于查看区别此次查询的类型,例如是:普通查询、联合查询、子查询等

  • simple:简单查询,查询中不包含子查询和UNION。
  • subquery:where语句里的子查询。例如:select * from a where a_id in (select b_id from b)。
  • derived:衍生查询。from语句里包含子查询。例如:select count(*) from (select * from a) as der。
  • primary:子查询的上层查询。
  • union:若第二个select出现在union之后,则会被标记为union,若union包含在from的子查询中,则会显示为derived。
  • union result:从union表中查询结果。

type:显示的是访问类型,结果也不同

  • system:表中只有一行数据。
  • const:根据索引直接一步就可以找到,例如SELECT * FROM table WHERE id=1。
  • eq_ref:用于主键或者唯一索引的扫描。例如id是表中主键, SELECT * FROM t1,t2 WHERE t1.id=t2.id。
  • ref:非唯一性索引,我们要扫描某个索引匹配的所有行。
  • range:索引的范围查询,例如用了in、between、<、>等范围查询。
  • index:索引覆盖,扫描整个索引文件。
  • ALL:整张数据表表都需要扫描,一般出现在没有索引的列。

性能的好坏顺序(优化最好到range)
system>const>eq_ref>ref>range>index>ALL


possible_key和key:一个代表可能使用的索引,一个代表当前使用的索引

  • possible_keys:显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引奖杯列出,但不一定被查询实际使用。
  • key:实际使用的索引,若为null,则没有使用到索引。(两种可能,①没建立索引。②建立索引,但索引失效)。查询中若使用了覆盖索引,则该索引仅出现在key列表中。

key_len:本次所选择的索引长度有多少字节,通常我们可借此判断联合索引有多少列被选择了。

  • 一般地,key_len 等于索引列类型字节长度,例如int类型为4-bytes,bigint为8-bytes;
    如果是字符串类型,还需要同时考虑字符集因素,例如:CHAR(30) UTF8则key_len至少是90-bytes;
  • 若该列类型定义时允许NULL,其key_len还需要再加 1-bytes;
  • 若该列类型为变长类型,例如 VARCHAR(TEXT\BLOB不允许整列创建索引,如果创建部分索引,也被视为动态列类型),其key_len还需要再加 2-bytes;

例:
MySQ慢查询+索引与执行计划_第12张图片



rows:根据索引的情况估算出执行本次SQL语句要查询的行数。

Extra:包含了不能在其它列显示,但十分重要的额外信息。

  • Using filesort :代表用了文件排序,索引没有用上,可以进行优化
  • Using temporary:代表使用了临时表保存中间结果,Mysql常在查询结果中使用,特别是加入了排序,说明可以进行优化操作
  • Using index:使用了索引覆盖,什么是索引覆盖?就是说可以直接在索引表中查询到SQL语句中查询的值而不用回表。覆盖索引必须要存储索引列的值,所以mysql只能用B-tree索引做覆盖索引
    MySQ慢查询+索引与执行计划_第13张图片

四.sql优化

1.优化策略

(1) 联合索引,尽量全值匹配。也就是where条件最好把这几个列都添加上。

在这里插入图片描述
(2)联合索引,必须符合左匹配原则。也就是限定查询条件必须从最左边的列开始。否则索引回失效,例如:
在这里插入图片描述
在这里插入图片描述
可以执行,但是把name删除后,索引无法生效。如果去掉age,只有name是生效的,pos无效。因为在B树的叶子节点中,是按列名的顺序进行排列的,少了中间列,则无法查找到最后一列的数据。
在这里插入图片描述
左匹配只是不能缺少,交换位置是可以的。


(3)不要在索引列上做任何的操作(计算,函数,类型转换),会造成索引的失效


(4)尽量使用覆盖查询(索引列和查询列一致), 少使用select


(5)在使用不等于(< > !=) 的范围查找时,索引会失效,在这种情况下使用覆盖索引会使索引重新生效

MySQ慢查询+索引与执行计划_第14张图片

使用覆盖索引
在这里插入图片描述

(6)注意null和not对索引是有影响的

如果列设置为not null,那么你去搜索null,sql语句是不会生效的
MySQ慢查询+索引与执行计划_第15张图片
如果设置为not null的列,你去查找not null,等同于范围查询,除了在覆盖索引的情况下,其余情况都会导致索引失效。
MySQ慢查询+索引与执行计划_第16张图片
(7).Like查询可能导致全表扫描,从而引发全表扫描,%写在前面会导致索引失效,在后不会
MySQ慢查询+索引与执行计划_第17张图片
MySQ慢查询+索引与执行计划_第18张图片
(8)字符串类型的数据,不加引号,会导致索引失效
MySQ慢查询+索引与执行计划_第19张图片

(9)OR改UNION查询效率高
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。与OR在查询上效果相同,但索引不会失效。
MySQ慢查询+索引与执行计划_第20张图片
or也属于范围查询,会带来索引的失效。
MySQ慢查询+索引与执行计划_第21张图片
(10)如果复制表,采用Insert方法效率太慢,将上一张表的数据利用OTFILE语句输出为文件,然后用LOAD语句,加载到新的表中,复制速度比纯INSERT快20倍左右
MySQ慢查询+索引与执行计划_第22张图片



总结:在索引失效的各种情况下,使用覆盖索引必然使可以生效的,但是尽量不去这么做,因为索引覆盖不是万能的,可能不符合业务需求。正确的方法是按照策略的错误点去改正。
另外在范围查询的非覆盖查询的条件下,索引都是会失效的

你可能感兴趣的:(MySQl)