索引优化分析_explain

  • 1.索引优化分析_explain查看执行计划
  • 1.1 MySql Query Optimizer
  • 1.2.Explain
  • 1.2.1.是什么(查看执行计划)
  • 1.2.2.能干嘛
  • 1.2.3.怎么玩
  • 1.2.4.建表语句
  • 2.索引优化分析_explain_各字段解释
  • 2.1.id★
  • 2.2.select_type
  • 2.3.table
  • 2.4.partitions
  • 2.5.type★
  • 2.5.1.system
  • 2.5.2.const
  • 2.5.3.eq_ref
  • 2.5.4.ref *
  • 2.5.5.range *
  • 2.5.6.Index
  • 2.5.7.all
  • 2.6.possible_keys
  • 2.7.key
  • 2.8.key_len ★
  • 2.9.ref
  • 2.10.rows★
  • 2.11.filtered
  • 2.12.Extra★
  • 2.12.1.Using filesort *
  • 2.12.2.Using temporary *
  • 2.12.3.Using index *
  • 2.12.4.Using where
  • 2.12.5.using join buffer *
  • 2.12.6.impossible where


1.索引优化分析_explain查看执行计划

1.1 MySql Query Optimizer

  1. MySQL中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间)
  2. 当客户端向MySQL 请求一条Query,命令解析器模块完成请求分类,区别出是 SELECT 并转发给MySQL Query Optimizer时,MySQL Query Optimizer
    首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。并对 Query
    中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。然后分析 Query 中的 Hint
    信息(如果有),看显示Hint信息是否可以完全确定该Query 的执行计划。如果没有 Hint 或Hint
    信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据 Query 进行写相应的计算分析,然后再得出最后的执行计划。

1.2.Explain

1.2.1.是什么(查看执行计划)

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

官网介绍 https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

索引碎片和优化_mysql

1.2.2.能干嘛

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

1.2.3.怎么玩

Explain + SQL语句

索引碎片和优化_mysql_02


EXPLAIN输出项(来源于mysql5.7文档)

Column

JSON Name

Meaning

id

select_id

The SELECT identifier

select_type

None

The SELECT type

table

table_name

The table for the output row

partitions

partitions

The matching partitions

type

access_type

The join type

possible_keys

possible_keys

The possible indexes to choose

key

key

The index actually chosen

key_len

key_length

The length of the chosen key

ref

ref

The columns compared to the index

rows

rows

Estimate of rows to be examined

filtered

filtered

Percentage of rows filtered by table condition

Extra

None

Additional information

1.2.4.建表语句

CREATE TABLE t1(id INT(10) AUTO_INCREMENT,content  VARCHAR(100) NULL ,  PRIMARY KEY (id));
 CREATE TABLE t2(id INT(10) AUTO_INCREMENT,content  VARCHAR(100) NULL ,  PRIMARY KEY (id));
 CREATE TABLE t3(id INT(10) AUTO_INCREMENT,content  VARCHAR(100) NULL ,  PRIMARY KEY (id));
 CREATE TABLE t4(id INT(10) AUTO_INCREMENT,content  VARCHAR(100) NULL ,  PRIMARY KEY (id));
 
 INSERT INTO t1(content) VALUES(CONCAT('t1_',FLOOR(1+RAND()*1000))); 
 INSERT INTO t2(content) VALUES(CONCAT('t2_',FLOOR(1+RAND()*1000)));  
 INSERT INTO t3(content) VALUES(CONCAT('t3_',FLOOR(1+RAND()*1000)));    
 INSERT INTO t4(content) VALUES(CONCAT('t4_',FLOOR(1+RAND()*1000)));

2.索引优化分析_explain_各字段解释

2.1.id★

1.select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
2.三种情况
1)id相同,执行顺序由上至下

select * from t1,t2,t3;

索引碎片和优化_sql_03

2)id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

explain select t1.id from t1 where t1.id = (select t2.id from t2 where t2.id = (select t3.id from t3 where t3.content='t3_897'));

索引碎片和优化_mysql_04

id相同,不同,同时存在;

id如果相同,可以认为是一组,从上往下顺序执行;

在所有组中,id值越大,优先级越高,越先执行;

关注点:id号每个号码,表示一趟独立的查询。一个sql的查询趟数越少越好。

2.2.select_type

1.有哪些

索引碎片和优化_数据库_05

2.查询的类型,主要是用于区别 普通查询、联合查询、子查询等的复杂查询

1)SIMPLE

简单的 select 查询,查询中不包含子查询或者UNION

EXPLAIN SELECT * FROM t1;

索引碎片和优化_sql_06


2)PRIMARY

查询中若包含任何复杂的子部分,最外层查询则被标记为primary

EXPLAIN select t1.id from t1 where t1.id = (select t2.id from t2 where t2.id = (select t3.id from t3 where t3.content='t3_897'));

索引碎片和优化_sql_07

3)SUBQUERY

在SELECT或WHERE列表中包含了子查询

索引碎片和优化_字段_08


4)DEPENDENT SUBQUERY

 在SELECT或WHERE列表中包含了子查询,子查询基于外层

EXPLAIN SELECT * FROM t3 WHERE id = ( SELECT id FROM t2 WHERE content = t3.content);

索引碎片和优化_mysql_09

5)UNCACHEABLE SUBQUREY

表示这个subquery的查询要受到外部系统变量的影响

EXPLAIN SELECT * FROM t3 WHERE id = ( SELECT id FROM t2 WHERE content = @@character_set_server);

索引碎片和优化_数据库_10

6)UNION

若第二个SELECT出现在UNION之后,则被标记为UNION; 若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED

EXPLAIN SELECT * FROM (SELECT * FROM t1 UNION SELECT * FROM t2) aa;

索引碎片和优化_字段_11


7)UNION RESULT

从UNION表获取结果的SELECT

索引碎片和优化_字段_12

2.3.table

显示这一行的数据是关于哪张表的

2.4.partitions

代表分区表中的命中情况,非分区表,该项为null

https://dev.mysql.com/doc/refman/5.7/en/alter-table-partition-operations.html

2.5.type★

索引碎片和优化_字段_13

1.访问类型排列

type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

system>const>eq_ref>ref>range>index>ALL
一般来说,得保证查询至少达到range级别,最好能达到ref

2.类型介绍

2.5.1.system

o表仅有一行记录,必须是系统表,这是const类型的特例,查询起来非常迅速。

explain SELECT * from mysql.proxies_priv WHERE `User`='root';

索引碎片和优化_索引碎片和优化_14

2.5.2.const

explain select * from t1 where id = 1;

索引碎片和优化_mysql_15

1.表示通过索引一次就找到了,const用于primary key或者unique索引。

2.因为只匹配一行数据,所以很快 如将主键置于where列表中,MySQL就能将该查询转换为一个常量

2.5.3.eq_ref

explain select * from t1,t2 where t1.id = t2.id;

索引碎片和优化_数据库_16

唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见主键或唯一索引扫描

2.5.4.ref *

create index idx_content on t1(content);
EXPLAIN SELECT * FROM t1, t2 WHERE t1.content = t2.content;

索引碎片和优化_sql_17


1.非唯一性索引扫描,返回匹配某个单独值的所有行. 本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而, 它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体

2.5.5.range *

explain select * from t2 where id >1 and id <5;

索引碎片和优化_mysql_18

1.只检索给定范围的行,使用一个索引来选择行。

2.key 列显示使用了哪个索引 一般就是在你的where语句中出现了between、<、>、in等的查询 这种范围索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束语另一点,不用扫描全部索引。

2.5.6.Index

explain select id from t1;

索引碎片和优化_字段_19


1.出现index是sql使用了索引但是没用通过索引进行过滤,一般是使用了覆盖索引或者是利用索引进行了排序分组

2.Full Index Scan,index与ALL区别为index类型只遍历索引树。

3.这通常比ALL快,因为索引文件通常比数据文件小。

4.也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读的

2.5.7.all

explain select * from t2;

索引碎片和优化_sql_20


Full Table Scan,将遍历全表以找到匹配的行

2.6.possible_keys

显示可能应用在这张表中的索引,一个或多个。 查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用

2.7.key

实际使用的索引。如果为NULL,则没有使用索引

索引碎片和优化_mysql_21

2.8.key_len ★

okey_len表示索引使用的字节数,根据这个值可以判断索引的使用情况,特别是在组合索引的时候,判断该索引有多少部分被使用到非常重要。值越大越好

索引碎片和优化_字段_22


如何计算

第一组

key_len=age的字节长度+name的字节长度=(4+1) + ( 20*3+2+1) = 5+63 = 68

第二组

key_len=age的字节长度=4+1=5

索引碎片和优化_索引碎片和优化_23

key_len的长度计算公式:

varchr(10)变长字段且允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+1(NULL)+2(变长字段)
varchr(10)变长字段且不允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+2(变长字段)
char(10)固定字段且允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+1(NULL)
char(10)固定字段且不允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)

2.9.ref

显示将哪些列或常量与键列中命名的索引进行比较,以从表中选择行。

explain select * from t1,t2 where t1.id = t2.id;

索引碎片和优化_mysql_24

2.10.rows★

rows列显示MySQL认为它执行查询时必须检查的行数。值越小越好

2.11.filtered

o这个字段表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意是百分比,不是具体记录数

2.12.Extra★

包含不适合在其他列中显示,但十分重要的额外信息

2.12.1.Using filesort *

出现filesort的情况:order by 没有用上索引

索引碎片和优化_字段_25


优化后**(给deptno和ename字段建立复合索引)**,去掉filesort

索引碎片和优化_sql_26

1.查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度

2.说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。

MySQL中无法利用索引完成的排序操作称为“文件排序”

2.12.2.Using temporary *

1.出现Using temporary情况:分组没有用上索引。产生临时表。注意:分组操作是需要先排序后分组的。所以,也会出现Using filesort。

2.优化前存在 using temporary 和 using filesort

索引碎片和优化_字段_27

优化后(给deptno和ename建立复合索引)去掉using temporary 和 using filesort,性能发生明显变化:

索引碎片和优化_mysql_28

使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序order by 和分组查询group by。

2.12.3.Using index *

表示使用了覆盖索引 [content是一个索引]

索引碎片和优化_数据库_29


如果同时出现using where,表明索引被用来执行索引键值的查找;

索引碎片和优化_索引碎片和优化_30

如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。

2.12.4.Using where

表明使用了where过滤!

2.12.5.using join buffer *

如果有它则表明关联字段没有使用索引!

索引碎片和优化_sql_31

使用了连接缓存

2.12.6.impossible where

索引碎片和优化_mysql_32


where 后面筛选条件有错误