🍖索引原理与慢查询优化

引入

本篇博客偏理论, 将会介绍如下知识:html

  • 索引介绍
  • 索引原理
  • 索引的数据结构(二叉树--->平衡二叉树--->B树--->B+树)
  • 汇集索引与辅助索引
  • MySQL索引管理
  • 建立和删除索引的语法
  • 建立索引后的测试 (查询速度的变化)
  • 如何正确使用索引
  • 回表
  • 覆盖索引
  • 联合索引
  • 最左前缀匹配
  • 索引下推
  • MySQL查询优化 : explain
  • 慢查询优化的基本步骤
  • 慢日志管理

一.索引介绍

1.什么是索引

  • 索引是对数据库表中一列或多列的值进行排序的一种数据结构, 使用索引能够快速访问数据库表中的特定信息
  • 为数据库创建索引, 就比如为书创建目录

2.为何要有索引

  • 优化数据查询效率

数据库的数据通常存储在磁盘中, 相比较内存, 磁盘的访问速度较慢索引就是能够帮助数据库快速从磁盘中找到数据的一种数据结构python

  • 注意 : 建立索引后会下降增、删、改的效率

虽然会下降, 可是通常的应用系统,读写比例在10:1左右,并且插入操做和通常的更新操做不多出现性能问题,遇到最多的,也是最容易出问题的,仍是一些复杂的查询操做,因此查询语句的优化显然是重中之重mysql

3.为表建立的索引是否是越多越好?

  • 多数状况下, 咱们知道索引可以提升查询效率, 但过多也会影响应用程序效率, 怎么加才是关键
  • 一个应用程序的设计, 数据上过多或过少的索引都会引起应用程序的效率问题, 因此咱们须要找到一个平衡点
  • 当表有大量数据的状况下, 建立索引的速度会很慢, 而且对于写的性能也会大幅度下降

4.索引应该何时加才最合适

  • 任何一个软件都有其吸引用户的亮点, 亮点背后对应的是热数据, 无疑开发人员对热数据的所对应的数据库字段有哪些, 应该在开发软件的过程当中就提早为相应的字段加上索引, 而不是等软件上线后让DBA发现慢查询sql后再作处理

缘由 :sql

1.一个软件慢会影响用户体验, 可是慢的缘由有不少, 你不能当即肯定就是 SQL 的问题, 当你定位到 SQL 问题的时候就已通过去好久了, 问题没有获得及时的解决数据库

2.大多数DBA都是管理型DBA而非开发型, 因此即使是DBA从日志中看到了慢查询sql, 也会由于其不懂业务而很难分析出慢的缘由windows

二.索引原理

1.索引的原理

  • 经过不断的缩小想要查询的数据范围筛选出最终的结果

就好比买火车票(无索引) : 若是没有12360火车票订购软件, 摆在咱们面前的就是成千上万辆火车, 选择那一辆的条件有火车类型、出发和终点、时间等等, 咱们须要一辆一辆火车去比对本身的筛选条件, 运气好第一辆就是要找的火车, 运气很差第一千辆才是要找的火车缓存

加入索引 : 如今咱们只须要在12360软件上选择高铁, 就能筛选掉不是高铁的火车, 缩小了查询范围; 再输入出发点和终点, 又缩小了查询范围; 再输入时间, 范围又减小, 最终找到本身须要的车次, 由不固定查询次数变成很小的固定查询次数数据结构

2.磁盘I/O与预读

  • I\O延迟

IO延迟 = 平均寻道时间 + 平均延迟时间(通常为9ms)--->例子:假设当前硬盘转轴(盘片)转速是7200/min,也就是120/s,那么转一圈须要花费1/120≈8ms,半圈也就是4ms(假设找到数据要半圈)函数

9ms左右对于咱们来说很短, 但对于一台500-MIPS的机器来讲每秒能够执行5亿条指令, 换句话说执行一次IO的时间能够执行40万条指令,数据库动辄十万百万乃至千万级数据,每次9毫秒的时间, 这简直是场灾难性能

  • 预读

考虑到磁盘IO是很是高昂的操做,计算机操做系统作了一些优化,当一次IO时,不光把当前磁盘地址的数据,而是把相邻的数据也都读取到内存缓冲区内,由于局部预读性原理告诉咱们,当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。每一次IO读取的数据咱们称之为一页(page)。具体一页有多大数据跟操做系统有关,通常为4k或8k,也就是咱们读取一页内的数据时候,实际上才发生了一次IO,这个理论对于索引的数据结构设计很是有帮助

三.索引的数据结构

索引的数据结构是 B+树, 而 B+树 是通过 二叉排序树 到 二叉平衡树 再到 B树 最后到 B+树 演变过来的, 下面简单介绍一下:

1.二叉排序树(二叉查找树)

  • 顶端的节点咱们称为根节点,没有子节点的节点咱们称之为叶节点(就是最下面一排)

对于一列数字 : 五、六、七、八、九、10

image-20210224174432982

  • 若是咱们须要找到 key=9 的节点, 先将 9 与根节点比较, 大于根节点, 因而往右边找; 继续与右边的 10 比较, 小于, 因而往左边找, 正好找到九

利用二叉排序树咱们只须要3次便可找到匹配的数据; 若是在数字列中一条条的查找的话,咱们须要5次才能找到

2.平衡二叉树(AVL树)

  • 平衡二叉树能够说是二叉排序树的改进版, 是特殊的二叉排序树

上面咱们讲解了利用二叉排序树能够快速的找到数据; 可是,若是上面的二叉排序树是这样的构造:

image-20210224175721158

平均查找长度是3, 若是咱们调整一下关键字的序列

image-20210224180204999

调整以后平均查找长度是 2.2, 从上面咱们能够看出平均查找长度与数的高度有关, 平均查找长度越小, 查找速度就越快, 因此咱们应该尽量的让这棵树矮

  • 怎么判断一颗二叉树是不是平衡二叉树?

这里引入了平衡因子的概念, 左子树的高度减右子数的高度就是平衡因子, 平衡因子的绝对值小于或等于一就是平衡二叉树, 大于一就是非平衡二叉树, 以下图平衡因子为 4 就是非平衡二叉树

image-20210224181012776

咱们调整一下关键字序列, 各子数平衡因子绝对值都小于或等于 1, 那么这就是一颗平衡二叉树

image-20210224181425555

3.B 树 ( Balanced Tree)多路平衡查找树

  • 咱们知道平衡二叉树每一个节点只能存储一个键值和数据

若是咱们要存储海量的数据呢?能够想象到二叉树的节点将会很是多,高度也会及其高,咱们查找数据时也会进行不少次磁盘IO,咱们查找数据的效率将会极低

  • 为了解决平衡二叉树的这个弊端,咱们应该寻找一种单个节点能够存储多个键值和数据的平衡树, 也就是 B树

img

从上图能够看出,B树相对于平衡二叉树,每一个节点(B树中节点称之为页)存储了更多的键值(key)和数据(data),而且每一个节点拥有更多的子节点,子节点的个数通常称为阶,上述图中的B树为3阶B树,高度也会很低。 基于这个特性,B树查找数据读取磁盘的次数将会不多,数据的查找效率也会比平衡二叉树高不少

假设每一个节点能够储存两个值(不表明只能存两个), 咱们找到75:

  • 先与 页1 比较,在 35 右边找到 p3指针 定位到 页4
  • 与 页4 中的索引对比, 在 65-87 之间, 找到指针 p2, 定位到 页10
  • 与 页10 中的索引对比, 找到相对应的 75

4.B+ 树

  • B+ 树是对 B树的进一步优化

img

  • 经过上图咱们来对比下 B+ 树与 B树的不一样:
  • B+ 树非叶子节点上是不存储数据的,仅存储键值,而 B 树节点中不只存储键值,也会存储数据

  • 之因此这么作是由于在数据库中页的大小是固定的,InnoDB 中页的默认大小是 16KB。若是不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来咱们查找数据进行磁盘的 IO 次数又会再次减小,数据查询的效率也会更快

  • B+ 树的阶数是等于键值的数量的,若是咱们的 B+ 树一个节点能够存储 1000 个键值,那么 3 层 B+ 树能够存储 1000×1000×1000=10 亿个数据。

  • 通常根节点是常驻内存的,因此通常咱们查找 10 亿数据,只须要 2 次磁盘 IO

  • 3层的b+树能够表示上百万的数据,若是上百万的数据查找只须要两次IO,性能提升将是巨大的,若是没有索引,每一个数据项都要发生一次IO,那么总共须要百万次的IO,显然成本很是很是高

  • B+ 树的两种性质
  • 索引字段要尽可能的小 : 磁盘块的大小也就是一个数据页的大小,是固定的. 若是数据项占的空间越小,数据项的数量越多,树的高度就越低, 查询过的IO次数就越少. 这就是为何每一个数据项,即索引字段要尽可能的小,好比int占4字节,要比bigint8字节少一半。这也是为何b+树要求把真实的数据放到叶子节点而不是内层节点,一旦放到内层节点,磁盘块的数据项会大幅度降低, 降低则会致使每层可存储的数据就少, 由于磁盘块是固定的, 从而要增长层次, 进而致使树增高, 树增高意味着找到底层数据的IO次数增多, 致使查询速度大幅度降低
  • 索引的最左匹配特性 : 当b+树的数据项是复合的数据结构,好比(name,age,sex)的时候,b+数是按照从左到右的顺序来创建搜索树的. 好比当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来肯定下一步的所搜方向,若是name相同再依次比较age和sex,最后获得检索的数据. 但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪一个节点,由于创建搜索树的时候name就是第一个比较因子,必需要先根据name来搜索才能知道下一步去哪里查询。 好比当(张三,F)这样的数据来检索时,b+树能够用name来指定搜索方向,但下一个字段age的缺失,因此只能把名字等于张三的数据都找到,而后再匹配性别是F的数据了, 这个是很是重要的性质,即索引的最左匹配特性

5.总结 B+ 树优势

  • 在二叉树、平衡二叉树、B树的基础上作了进一步优化, 只有叶子节点放真正的数据,这意味着在等量数据的前提下,B+树的高度是最低的
  • B+的叶子节点都是排好序的,这意味着在范围查询上,B+树比B树更快,快就快在一旦找到一个树叶节点,就不须要在再从树根查起了

四.汇集索引与辅助索引

数据库中的 B+树 索引能够分为汇集索引(clustered index)和辅助索引(secondary index), 汇集索引与辅助索引相同的是:无论是汇集索引仍是辅助索引,其内部都是B+树的形式,即高度是平衡的, 不一样的是 :

汇集索引的叶子节点存放的是一整行完整的信息, 而辅助索引的叶子节点存放的并不是完整信息(下面介绍)

1.汇集索引 (Clustered Index)

InnoDB 汇集索引的叶子节点存储行记录,所以 InnoDB 必需要有且只有一个汇集索引

  • 若是表定义了 PK (Primary Key,主键),那么 PK 就是汇集索引

  • 若是表没有定义 PK,则第一个不为空且惟一(NOT NULL UNIQUE) 的列就是汇集索引

  • 不然 InnoDB 会另外建立一个隐藏的 ROWID 做为汇集索引

因为这种机制是直接定位行记录,所以使得基于 PK 的查询速度很是快

2.辅助索引( Secondary Index )

表中除了汇集索引外其余索引都是辅助索引(Secondary Index,也称为非汇集索引)

  • 与汇集索引的区别是:辅助索引的叶子节点不包含行记录的所有数据。叶子节点除了包含键值之外,每一个叶子节点中的索引行中还包含一个书签(bookmark)。该书签用来告诉InnoDB存储引擎去哪里能够找到与索引相对应的行数据

  • 辅助索引的存在并不影响数据在汇集索引中的组织,所以每张表上能够有多个辅助索引,但只能有一个汇集索引

  • 当经过辅助索引来寻找数据时,InnoDB存储引擎会遍历辅助索引并经过叶子级别的指针得到指向主键索引的主键,而后再经过主键索引来找到一个完整的行记录

五.Mysql 索引管理

1.功能

  • 索引的功能就是加速查找
  • mysql中的primary key,unique,联合惟一也都是索引,这些索引除了加速查找之外,还有约束的功能

2.mysql 中经常使用的索引(键)

  • 普通索引: index 加速查找
  • 惟一索引:
    • 主键索引: primary key 加速查找+约束
    • 惟一索引: unique key 加速查找+约束
  • 联合索引:
    • 联合主键索引: primary key
    • 联合惟一索引: unique(字段1, 字段2, ...)
    • 联合普通索引: unique(字段1, 字段2, ...)

上面的三种索引, 惟一索引除了能够增长查询速度以外各自还具备约束条件, 而普通索引index key没有任何的约束条件,只是用来帮助你加快速查询数据

注意:联合索引不是用来加速查询用的,不在咱们的而研究范围以内

3.索引的两大类型

  • 咱们能够在建立索引的时候, 为其指定索引类型(两类)
hash类型的索引:查询单条快,范围查询慢
btree类型的索引:b+树,层数越多,数据量指数级增加(咱们就用它,由于innodb默认支持它)
  • 不一样的存储引擎支持的索引类型也不同
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引
Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引
Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引

六.建立和删除索引语法

1.建立的三种方法

  • 语法
🍓方式一 : 建立表时建索引
create table [表名] (
    [unique|fulltext|spatial] [index|key] [索引名] [字段名(长度)] [asc|desc]
    );
    
🍓方式二 : 在已存在的表上建立
create [unique|fulltext|spatial] index [索引名]
    on [表名] [字段名(长度)] [asc|desc];

🍓方式二 : alter 在已存在的表上建立索引
alter table [表名] add [unique|fulltext|spatial] index 
    [索引名] [字段名(长度)] [asc|desc];
  • 示例代码
🍓方式一
create table t01(
    id int,
    name char(10),
    age int,
    sex enum("male","female"),
    unique key unique_id(id),
    index index_name(name)  # index没有key
);

🍓方式二
create index index_age on t01(age);

🍓方式三
alter table t01 add index index_sex(sex);

2.删除索引

drop index [索引名] on t01;    # 语法
drop index index_age on t01;  # 示例

七.索引测试

1.先准备一张表, 并插入大量的数据

🍓建立表
create table t01(
    id int,
    name varchar(10),
    sex enum("male","female"),
    email varchar(18)
);

🍓建立存储过程,进行自动插入记录
delimiter %%%
create procedure p01()
begin
    declare i int default 1;
    while(i<3000000)do
        insert t01 value(i,"shawn","male",concat("shawn",i,"@163.com"));
        set i=i+1;
    end while;
end %%%
delimiter ;

🍓查看存储过程
show create procedure p01\G  # \G 垂直显示结果

🍓调用存储过程
call p01();  # windows执行测试大概一个半小时,3百万条记录,200多M

🍓删除存储过程
drop procedure p01;

image-20210225095534649

2.没有创建索引的状况下测试查询速度

select * from t01 where id=3000000;

没有索引,mysql不知道有没有这条记录, 因此从头至尾的对记录进行遍历,有多少磁盘块就要进行多少I\O,速度很慢

image-20210225095645650

3.为表的某个字段创建索引(表已经存在大量记录,建立速度会很慢)

create index index_id on t01(id);  # 为 id 字段创建普通索引

观察 data 文件夹下的 t01 表数据文件大小增长了

image-20210225100323340

image-20210225110724526

4.使用创建了索引的字段设置为条件进行查询

select * from t01 where id=3000000;  # 能够观察到速度明显的提高

image-20210225101246174

5.步骤分析

  • mysql先去索引表里根据 b+树 的搜索原理很快搜索到 id 等于3000000的记录,直接命中索引, IO大大下降,于是速度明显提高

  • 咱们以没有创建索引的字段设置为条件来进行查询, 能够发现速度依然很慢

    select * from t01 email="shawn3000000@163.com";  # 而且记录越大查询越慢

    image-20210225110358350

  • 对 email 字段创建索引试试

create index index_email on t01(email);  # 字段数据越大,创建的时间越长(因此建议不要使用数据很大的字段创建索引,这里只是作实验)
select * from t01 where email="shawn3000000@163.com";  # 再去查询,能够发现速度是数量级的提高

image-20210225111132774

八.正确使用索引

并非说建立了索引就必定能加速查询, 有些状况就算命中了索引也未必能起到很好的提速效果, 下面来测试一下各类状况 (若是不想看过程,能够直接看小结末尾的结论)

1.范围查询状况 : 或者说条件不明确, 条件中有 : >、>=、<、<=、!= 、between...and...、like

  • 大小于 : >、<

image-20210225145700684

  • 不等于 : !=

image-20210225145844390

  • between...and...

image-20210225150055303

  • 模糊匹配 : like

like

2.区分度状况 : 区分度表示字段不重复的比例, 区分度越大, 扫描的速度就越快,像主键惟一, 而性别字段区分度就很低

image-20210225153807708

出现上面的状况就是由于字段的区分度过低, 在 B+树 中对于这些字段没法比较大小, 由于值都是相等的, 毫无疑问,只能增长树的高度来保证这些数据的存储, 树的高度越高, 查询速度就越慢

3.=和in能够乱序,好比a = 1 and b = 2 and c = 3 创建(a,b,c)索引能够任意顺序,mysql的查询优化器会帮你优化成索引能够识别的形式

4.索引列不要参与计算或者函数, 好比薪资乘与12 : 不要使用字段相乘(salary*12=10000), 可使用该字段所对应的值相乘(salary=10000*12)

image-20210225155533918

5.索引下推技术

🍓"and"与"or"的逻辑
    [条件1] and [条件2] : 全部条件都成立才算成立,但凡要有一个条件不成立则最终结果不成立
    [条件1] or [条件2] : 只要有一个条件成立则最终结果就成立

🍓"and"的工做原理
    条件:        
        a = 10 and b = 'xxx' and c > 3 and d =4    
    索引:        
        制做联合索引(d,a,b,c)    
    工做原理:        
        对于连续多个and:mysql会按照联合索引,从左到右的顺序找一个区分度高的索引字段(这样即可以快速锁定很小的范围),加速查询,即按照d—>a->b->c的顺序

🍓"or"的工做牌原理
    条件:        
        a = 10 or b = 'xxx' or c > 3 or d =4    
    索引:        
        制做联合索引(d,a,b,c)            
    工做原理:        
        对于连续多个or:mysql会按照条件的顺序,从左到右依次判断,即a->b->c->d

6.最左前缀匹配原则

7.总结 (怎么创建索引能提升查询效率)

  • 对区分度高而且占用空间小的字段创建索引
  • 针对范围查询命中了索引,若是范围很大,查询效率依然很低,如何解决
    • 要么把范围缩小
    • 要么就分段取值,一段一段取最终把大范围给取完
  • 不要把查询字段放到函数或者参与运算
  • 索引下推技术,mysql自动选择查询速度最优的那条语句 (默认是开启)
  • 索引覆盖 (下面介绍)
  • 最左前缀匹配原则 (下面介绍)

8.其余注意事项

  • 避免使用select *
  • count(1)或count(列) 代替 count(*)
  • 建立表时尽可能时 char 代替 varchar
  • 表的字段顺序固定长度的字段优先
  • 组合索引代替多个单列索引(常用多个条件查询时)
  • 尽可能使用短索引
  • 使用链接(JOIN)来代替子查询(Sub-Queries)
  • 连表时注意条件类型需一致
  • 索引散列值(重复少)不适合建索引,例:性别不适合

九.回表、覆盖索引、联合索引、最左前缀

匹配原则、索引下推

1.建立一张表, 并插入记录

create table user(
    -> id int not null auto_increment,
    -> name char(16) not null,
    -> age int not null,
    -> primary key(id),            # id 为主键并设置索引(汇集索引)
    -> index index_name(name));    # name 字段设置索引(辅助索引)

insert user(name,age) value
    -> ("shawn",23),
    -> ("song",22),
    -> ("hai",20),
    -> ("xing",18),
    -> ("yanxi",45),
    -> ("zichen",25);

image-20210225170144065

2.回表

select * from user where id=2;

上面为主键查询方式, 即经过汇集索引, 能找到 id 为 2 的完整记录

select * from user where name="song";

上面为辅助索引查询方式, 则须要先搜索 name 索引树,获得 song 对应的 id 值为 2,再到 id 索引树搜索一次, 这个过程称为回表

  • 结论 : 因此基于辅助索引的查询须要多扫描一棵索引树。所以,咱们在应用中应该尽可能使用汇集索引

3.覆盖索引

select id from user where name="hai";

上面语句查询的条件是 name 字段, name 字段有索引树, 而且上面保存有 name 和 id 的值, 能够直接提供查询结果, 不须要进行回表操做, 也就是说, 在这个查询里面, 索引 name 已经覆盖了咱们所要查询的 id 字段需求, 这就称为覆盖索引

select age from user where name="xing";

上面语句经过 name 索引树找到 name 字段对应的 "xing" 和 id 值, 但没有 age 字段信息, 因而经过 id 字段进行回表操做查找到知足条件的数据

  • 回表操做无疑是下降效率的, 咱们能够再为 age 创建索引, 避免索引太多可能引发的效率问题, 也能够为其创建联合索引

4.联合索引、最左匹配原则

🔰联合索引是指对表上的多个列合起来作一个索引. 联合索引的建立方法与单个索引的建立方法同样,不一样之处在仅在于有多个索引列

🔰最左前缀匹配原则, 是很是重要的原则, mysql会从左到右进行匹配

  • 先删除 name 字段的索引, 再与 age 一块儿创建联合索引
drop index index_name on user;
create index index_name_age on user(name,age);  # 实际应用中应该把最经常使用的字段放在最左边
  • 当查询条件中出现如下字段,能够命中联合索引,由于符合最左前缀原则
select name,age from user where name="song";  # 条件字段 name
select name,age from user where name="song" and age>18;  # 条件字段 name + age
  • 查询条件中只出现一个 age 字段,不能命中联合索引
select name,age from user where age=2;  # 条件字段 age (不会走联合索引)

5.索引下推 (mysql自动开启)

索引下推(index condition pushdown )简称ICP,在Mysql5.6的版本上推出,用于优化查询

使用最左前缀匹配原则 + 联合查询能够加快查询速度, 若是咱们的条件存在范围查询, 那么 SQL 语句是怎么运行的呢?

select * from user where name like "s%" and age=22;

image-20210225180632714

如上表的记录, "s" 开头的记录有两条

  • Mysql 5.6 之前 没有索引递推这个优化
Innodb 会忽略 age 这个字段, 直接经过 name 来进行查询, 在(name,age)这个联合索引上找到两条结果, 而后拿到 id 为 1 和 2 进行"两次回表查询"
  • Mysql 5.6 及之后 添加了索引下推这个优化
Innodb 不会忽略 age 这个字段, 而是在索引内部就判断了 age 是否等于 22, 不等于 22 的记录直接跳过
所以在(name,age)这个联合索引上只匹配到一个记录, 此时拿着这一个 id 去回表到全部的数据只须要"回表一次"

十.MySQL查询优化 : explain

官方文档 : https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

ps : 强调 rows 是核心指标,绝大部分 rows 小的语句执行必定很快。因此优化语句基本上都是在优化rows

1.explain 是什么

explain 简称查看执行计划,使用 explain 关键字能够模拟优化器执行SQL查询语句,从而知道MySQL 是如何处理 SQL 语句的

2.explain 如何使用

语法 : explain + [SQL语句]

3.explain 的做用

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

4.执行计划表包含的字段信息

explain select * from t01;

image-20210225183254836

5.计划表字段说明

  • id 字段
字段 说明
id MySQL Query Optimizer 选定的执行计划中查询的序列号。表示查询中执行 select 子句或操做表的顺序,id值越大优先级越高,越先被执行; 若id 相同,执行顺序由上至下
  • select_type 字段
select_type 查询类型 说明
SIMPLE 简单的 select 查询,不使用 union 及子查询
PRIMARY 最外层的 select 查询
UNION UNION 中的第二个或随后的 select 查询,不 依赖于外部查询的结果集
DEPENDENT UNION UNION 中的第二个或随后的 select 查询,依 赖于外部查询的结果集
SUBQUERY 子查询中的第一个 select 查询,不依赖于外 部查询的结果集
DEPENDENT SUBQUERY 子查询中的第一个 select 查询,依赖于外部 查询的结果集
DERIVED 用于 from 子句里有子查询的状况。 MySQL 会 递归执行这些子查询, 把结果放在临时表里
UNCACHEABLE SUBQUERY 结果集不能被缓存的子查询,必须从新为外 层查询的每一行进行评估
UNCACHEABLE UNION UNION 中的第二个或随后的 select 查询,属 于不可缓存的子查询
  • table 字段
字段 说明
table 输出行所引用的表
  • type 字段

很是重要的项, 显示链接使用的类型, 按最优到最差的类型排序

type : 链接类型 说明
system 表仅有一行(=系统表)。这是 const 链接类型的一个特例
const const 用于用常数值比较 PRIMARY KEY 时。当 查询的表仅有一行时,使用 System
eq_ref const 用于用常数值比较 PRIMARY KEY 时。当 查询的表仅有一行时,使用 System
ref 链接不能基于关键字选择单个行,可能查找 到多个符合条件的行。 叫作 ref 是由于索引要 跟某个参考值相比较。这个参考值或者是一 个常数,或者是来自一个表里的多表查询的 结果值
ref_or_null 如同 ref, 可是 MySQL 必须在初次查找的结果 里找出 null 条目,而后进行二次查找。
index_merge 说明索引合并优化被使用了
unique_subquery 在某些 IN 查询中使用此种类型,而不是常规的 ref:value IN (SELECT primary_key FROM single_table WHERE some_expr)
index_subquery 在 某 些 IN 查 询 中 使 用 此 种 类 型 , 与 unique_subquery 相似,可是查询的是非惟一 性索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
range 只检索给定范围的行,使用一个索引来选择 行。key 列显示使用了哪一个索引。当使用=、 <>、>、>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 操做符,用常量比较关键字列时,可 以使用 range
index 全表扫描,只是扫描表的时候按照索引次序 进行而不是行。主要优势就是避免了排序, 可是开销仍然很是大
all 最坏的状况,从头至尾全表扫描
  • possible_keys 字段
字段 说明
possible_keys 指出 MySQL 能在该表中使用哪些索引有助于 查询。若是为空,说明没有可用的索引
  • key 字段
字段 说明
key MySQL 实际从 possible_key 选择使用的索引。 若是为 NULL,则没有使用索引。不多的状况 下,MYSQL 会选择优化不足的索引。这种情 况下,能够在 SELECT 语句中使用 USE INDEX (indexname)来强制使用一个索引或者用 IGNORE INDEX(indexname)来强制 MYSQL 忽略索引
  • key_len 字段
字段 说明
key_len 使用的索引的长度。在不损失精确性的状况 下,长度越短越好。
  • ref 字段
字段 说明
ref 显示索引的哪一列被使用了
  • rows 字段
字段 说明
rows MYSQL 认为必须检查的用来返回请求数据的行数
  • Extra 字段
extra 项 说明
Using filesort 表示 MySQL 会对结果使用一个外部索引排序,而不是从表里按索引次序读到相关内容。可能在内存或者磁盘上进行排序。MySQL 中没法利用索引完成的排序操做称为“文件排序”
Using temporary 表示 MySQL 在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by

6.示例

explain select * from t01 where id=100000;
explain select * from t01 where id>10000 and id<20000;
explain select * from t01 where id>20000;

image-20210225185120221

十一.慢查询优化的基本步骤

  • 先运行看看是否真的很慢,注意设置SQL_NO_CACHE
  • where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每一个字段分别查询,看哪一个字段的区分度最高
  • explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
  • order by limit 形式的sql语句让排序的表优先查
  • 了解业务方使用场景
  • 加索引时参照建索引的几大原则
  • 观察结果,不符合预期继续从第一个步骤开始分析

十二.慢日志管理

慢日志管理 : https://www.cnblogs.com/songhaixing/p/14448814.html

相关文章
相关标签/搜索