MySQL进阶(三)——索引优化分析(性能分析)

本篇文章主要是对MySQL学习时的一些总结,作为学习笔记记录

性能分析

性能下降原因

对于某些sql语句来说,会导致执行时间长,等待时间长的后果,从而造成整个sql语句的性能下降。导致sql性能下降的原因主要有:

  • 查询数据过多:能不能拆分,降低过滤条件
  • 关联了太多的表,太多join:使用之前尽量先过滤
  • 没有利用到索引(单值,复合)
    • 索引是针对列建立的,但并不可能对所有的数据列都建立索引
    • 同时索引也并不是越多越好,数据更新的同时,索引也会进行调整,因此过多的索引会降低性能
    • 而mysql也不会使用到所有的索引,只会根据其内部的算法找到一个合适的索引使用,因此索引需要建的准
    • 当条件比较多时候,可以使用复合索引,复合索引一般会首先使用
    • 而有些条件下,就算有索引在具体执行时也不会被使用
  • 服务器调优及各个参数设置(缓冲、线程数等)不合理

MySQL常见瓶颈

CPU

SQL中对大量数据进行比较、关联、排序、分组。其中最大的压力在于比较

IO

  • 实际内存满足不了缓存数据或排序等需要,导致产生大量 物理 IO
  • 查询执行效率低,扫描过多数据行

  • 不适宜的锁的设置,导致线程阻塞,性能下降
  • 死锁,线程之间交叉调用资源,导致死锁,程序卡住

服务器硬件

由于服务器硬件导致的性能瓶颈,此时可以通过top、free、iostat和vmstat来查看系统的性能状态

Explain

Explain是什么

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

Explain能做什么

通过Explain查看sql语句执行计划,可以查看到:

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

Explain怎么使用

EXPLAIN SQL语句;

Explain执行后包含的信息都有:

Explain字段解释

建表

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))) ;

id

select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序。总共存在三种情况:

  • id相同,执行顺序由上至下

MySQL进阶(三)——索引优化分析(性能分析)_第1张图片

此例中 先执行where后的第一条语句t1.id = t2.id通过t1.id关联t2.id,而 t2.id的结果建立在t2.id=t3.id的基础之上。

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

MySQL进阶(三)——索引优化分析(性能分析)_第2张图片

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

  • id相同又不同,同时存在
    • id如果相同,可以认为是一组,从上往下顺序执行;
    • 在所有组中,id值越大,优先级越高,越先执行
    • 衍生表 = derived2 --> derived + 2 (2 表示由 id =2 的查询衍生出来的表。type 肯定是 all ,因为衍生的表没有建立索引)

MySQL进阶(三)——索引优化分析(性能分析)_第3张图片

select_type

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

MySQL进阶(三)——索引优化分析(性能分析)_第4张图片

对于各类型的解释为:

SIMPLE:

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

MySQL进阶(三)——索引优化分析(性能分析)_第5张图片

PRIMARY

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

MySQL进阶(三)——索引优化分析(性能分析)_第6张图片

DERIVED

在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询, 把结果放在临时表里

MySQL进阶(三)——索引优化分析(性能分析)_第7张图片

SUBQUERY

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

MySQL进阶(三)——索引优化分析(性能分析)_第8张图片

DEPENDENT SUBQUERY

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

MySQL进阶(三)——索引优化分析(性能分析)_第9张图片

dependent subquery 与 subquery 的区别

  • dependent subquery : 子查询结果为 多值
  • subquery:查询结果为 单值 

UNCACHEABLE SUBQUREY

无法被缓存的子查询

上图种的 @@ 表示查的环境参数 ,没办法缓存。

UNION

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

MySQL进阶(三)——索引优化分析(性能分析)_第10张图片

UNION RESULT表示两个语句执行完后的结果

UNION RESULT

从UNION表获取结果的SELECT

MySQL进阶(三)——索引优化分析(性能分析)_第11张图片

table

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

type

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。

system

表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计

const

  • 表示通过索引一次就找到了,const用于比较primary key或者unique索引。
  • 因为只匹配一行数据,所以很快。如将主键置于where列表中,MySQL就能将该查询转换为一个常量

MySQL进阶(三)——索引优化分析(性能分析)_第12张图片

eq_ref

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

MySQL进阶(三)——索引优化分析(性能分析)_第13张图片

ref

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

MySQL进阶(三)——索引优化分析(性能分析)_第14张图片

MySQL进阶(三)——索引优化分析(性能分析)_第15张图片

range

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

MySQL进阶(三)——索引优化分析(性能分析)_第16张图片

MySQL进阶(三)——索引优化分析(性能分析)_第17张图片

index

  • Full Index Scan,index与ALL区别为index类型只遍历索引树
  • 这通常比ALL快,因为索引文件通常比数据文件小
  • 也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读的

MySQL进阶(三)——索引优化分析(性能分析)_第18张图片

all

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

MySQL进阶(三)——索引优化分析(性能分析)_第19张图片

MySQL进阶(三)——索引优化分析(性能分析)_第20张图片

index_merge

在查询过程中需要多个索引组合使用,通常出现在有 or 的关键字的sql中

ref_or_null

  • 对于某个字段既需要关联条件,也需要null值的情况下
  • 查询优化器会选择用ref_or_null连接查询

MySQL进阶(三)——索引优化分析(性能分析)_第21张图片

index_subquery

利用索引来关联子查询,不再全表扫描

MySQL进阶(三)——索引优化分析(性能分析)_第22张图片

MySQL进阶(三)——索引优化分析(性能分析)_第23张图片

unique_subquery 

  • 该联接类型类似于index_subquery
  • 子查询中的唯一索引

MySQL进阶(三)——索引优化分析(性能分析)_第24张图片

possible_keys

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

key

  • 实际使用的索引
  • 如果为NULL,则没有使用索引
  • 查询中若使用了覆盖索引,则该索引和查询的select字段重叠
  • 对比下图两个sql语句和key的值:当查询具体某一字段时,且那个字段有索引时,key值会显示为索引

MySQL进阶(三)——索引优化分析(性能分析)_第25张图片

key_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度

MySQL进阶(三)——索引优化分析(性能分析)_第26张图片

怎么计算?

MySQL进阶(三)——索引优化分析(性能分析)_第27张图片

上图中字符集为utf8格式,因此需要*3,动态类型包括varchar,detail text()截取字符串

MySQL进阶(三)——索引优化分析(性能分析)_第28张图片

  • 第一组:key_len=deptno(int)+null + ename(varchar(20)*3+动态  =4+1+20*3+2= 67
  • 第二组:key_len=deptno(int)+null=4+1=5

同时key_len字段能够帮你检查是否充分的利用上了索引

MySQL进阶(三)——索引优化分析(性能分析)_第29张图片

同样的使用了索引但是索引的涉及的字段却不同:

MySQL进阶(三)——索引优化分析(性能分析)_第30张图片

由上图可知,充分利用了索引的查询效率会更高。

ref

  • 显示索引的哪一列被使用了,如果可能的话,是一个常数
  • 哪些列或常量被用于查找索引列上的值

MySQL进阶(三)——索引优化分析(性能分析)_第31张图片

rows

  • rows列显示MySQL认为它执行查询时必须检查的行数
  • 越少越好
  • 对于InnoDB来说,该值只是一个估计,并不一定总是精确

Extra

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

Using filesort 

  • 说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
  • MySQL中无法利用索引完成的排序操作称为“文件排序”

出现filesort的情况:

MySQL进阶(三)——索引优化分析(性能分析)_第32张图片

优化后,不再出现filesort的情况(给 ename 加上了索引):

MySQL进阶(三)——索引优化分析(性能分析)_第33张图片

 

  • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
  • 当通过前面的查询语句筛选大部分条件后,只剩下很少的数据,using filesort 性能影响不大,此时需要综合考虑

Using temporary

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

优化前存在using  temporary和using  filesort:

MySQL进阶(三)——索引优化分析(性能分析)_第34张图片

create index idx_deptno_ename on emp(deptno,ename);后解决优化前存在的using  temporary和using  filesort问题,性能发生明显变化:

MySQL进阶(三)——索引优化分析(性能分析)_第35张图片

Using index

  • 表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错
  • 如果同时出现using where,表明索引被用来执行索引键值的查找
  • 如果没有同时出现using where,表明索引只是用来读取数据而非利用索引执行查找

覆盖索引(Covering Index)

  • 索引是高效找到行的一个方法,而一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行
  • 毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了
  • ①一个索引 ②包含了(或覆盖了)[select子句]与查询条件[Where子句]中 ③所有需要的字段就叫做覆盖索引

 如果有以下的sql语句:

select id , name from t_xxx where age=18;

若表中存在组合索引idx_id_name_age,此时该索引包含了(覆盖了)id、name、age三个字段,查询时直接读取建立了索引的列,而不需要查找所在行的其它数据,所以很高效。

注意:

  • 在数据量较大,固定字段查询情况多时可以使用这种方法
  • 如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降

Using where

表明使用了where过滤

using join buffer

  • 使用了连接缓存
  • 出现在当两个连接时
  • 驱动表(被连接的表,left join 左边的表,inner join 中数据少的表) 没有索引的情况下
  • 给驱动表建立索引可解决此问题,且 type 将改变成 ref

MySQL进阶(三)——索引优化分析(性能分析)_第36张图片

impossible where

where子句的值总是false,不能用来获取任何元组

MySQL进阶(三)——索引优化分析(性能分析)_第37张图片

select tables optimized away

在没有GROUP BY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化

在innodb中:

MySQL进阶(三)——索引优化分析(性能分析)_第38张图片

在Myisam中:

  • myisam中会维护总行数 (还有其他参数)这个参数,所以在执行查询时不会进行全表扫描,而是直接读取这个数,但会对增删产生一定的影响,根据业务情况决定谁好谁坏
  • innodb 中没有这个机制

你可能感兴趣的:(#,MySQL进阶,mysql,数据库,索引)