MySQL:explain(执行计划)详解

来源:互联网 发布:瑞典难民知乎 编辑:程序博客网 时间:2024/05/21 15:45
  1. 本文主要介绍了MySQL性能分析以及explain的使用,包括:组合索引、慢查询分析、MYISAMINNODB的锁定、MYSQL的事务配置项等,希望能够对您有所帮助。


1.使用explain语句去查看分析结果 

  1. explain select * from test1 where id=1;
  2. 会出现:id selecttype table type possible_keys key key_len ref rows extra各列。
 



  1. 其中,
  2. type=const 表示通过索引一次就找到了;
  3. key=primary的话,表示使用了主键;
  4. type=all, 表示为全表扫描;
  5. key=null 表示没用到索引。
  6. type=ref 因为这时认为是多个匹配行,在联合查询中,一般为REF

 

2.MYSQL中的组合索引 

  • 假设表有id,key1,key2,key3,把三者形成一个组合索引,则如: 

  1. where key1=....
  2. where key1=1 and key2=2
  3. where key1=3 and key2=3 and key3=2
  • 根据最左前缀原则,这些都是可以使用索引的,如from test where key1=1 order by key3。
  • 用explain分析的话,只用到了normal_key索引,但只对where子句起作用,而后面的order by需要排序。

 

3.使用慢查询分析(实用)

  1. my.ini中:
  2. long_query_time=1
  3. log-slow-queries=d:\mysql5\logs\mysqlslow.log
  • 把超过1秒的记录在慢查询日志中 
  • 可以用mysqlsla来分析之。
  • 也可以在mysqlreport中,有如 DMS分别分析了select ,update,insert,delete,replace等所占的百分比


4.MYISAM和INNODB的锁定 

  1. myisam中,用的是表锁,比如在多个UPDATE操作后,再SELECT时,会发现SELECT操作被锁定了,必须等所有UPDATE操作完毕后,才能SELECT
  2. innodb的话则不同了,用的是行锁,不存在上面问题。
  1. MyISAM InnoDB 讲解
    1. InnoDBMyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定。
    2. 基本的差别为:
    3. MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。
    4. MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,
    5. InnoDB提供事务支持以及外部键等高级数据库功能

  2.   
  3. 以下是一些细节和具体实现的差别:
  4.   1.InnoDB不支持FULLTEXT类型的索引。
  5.   2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,
  6. InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。
  7. 注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。
  8.   3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
  9.   4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
  10.   5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的
  11. 解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,
  12. 但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
    1. 另外,InnoDB表的行锁也不是绝对的,假如在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,
    2. 例如update table set num=1 where name like “%aaa%”
    3. 两种类型最主要的差别就是Innodb 支持事务处理与外键和行级锁。而MyISAM不支持.所以MyISAM往往就容易被人认为只适合在小项目中使用。
    4. 作为使用MySQL的用户角度出发,InnodbMyISAM都是比较喜欢的,
    5. 如果数据库平台要达到需求:99.9%的稳定性,方便的扩展性和高可用性来说的话,MyISAM绝对是首选。  
  13.   
  14. 原因如下:
  15.   1、平台上承载的大部分项目是读多写少的项目,而MyISAM的读性能是比Innodb强不少的。
  16.   2MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。
  17. 能加载更多索引,而Innodb是索引和数据是紧密捆绑的,没有使用压缩从而会造成InnodbMyISAM体积庞大不小。
  18.   3、经常隔12个月就会发生应用开发人员不小心update一个表where写的范围不对,导致这个表没法正常用了,
  19. 这个时候MyISAM的优越性就体现出来了,随便从当天拷贝的压缩包取出对应表的文件,随便放到一个数据库目录下,
  20. 然后dumpsql再导回到主库,并把对应的binlog补上
  21. 如果是Innodb,恐怕不可能有这么快速度,别和我说让Innodb定期用导出xxx.sql机制备份,
  22. 因为最小的一个数据库实例的数据量基本都是几十G大小。
  23.   4、从接触的应用逻辑来说,select count(*) order by 是最频繁的,大概能占了整个sql总语句的60%以上的操作,
  24. 而这种操作Innodb其实也是会锁表的,很多人以为Innodb是行级锁,那个只是where对它主键是有效,非主键的都会锁全表的。
  25.   5、还有就是经常有很多应用部门需要我给他们定期某些表的数据MyISAM的话很方便,只要发给他们对应那表的frm.MYD,MYI的文件让他们自己在对应版本的数据库启动就行,
  26. Innodb就需要导出xxx.sql了,因为光给别人文件,受字典数据文件的影响,对方是无法使用的。
  27.   6、如果和MyISAMinsert写操作的话,Innodb还达不到MyISAM的写性能,如果是针对基于索引的update操作,
  28. 虽然MyISAM可能会逊色Innodb,但是那么高并发的写,从库能否追的上也是一个问题,还不如通过多实例分库分表架构来解决。
  29.   7、如果是用MyISAM的话,merge引擎可以大大加快应用部门的开发速度,
  30. 他们只要对这个merge表做一些select count(*)操作,非常适合大项目总量约几亿的rows某一类型(如日志,调查统计)的业务表。
  31.    当然Innodb也不是绝对不用,用事务的项目就用Innodb的。
  32. 另外,可能有人会说你MyISAM无法抗太多写操作,但是可以通过架构来弥补。

5.MYSQL的事务配置项 

  1. innodb_flush_log_at_trx_commit=1
  2. 表示事务提交时立即把事务日志flush写入磁盘,同时数据和索引也更新,很费性能。
  3. innodb_flush_log_at_trx_commit=0
  4. 事务提交时,不立即把事务日志写入磁盘,每隔1秒写一次,MySQL挂了可能会丢失事务的数据。
  5. innodb_flush_log_at_trx_commit=2 ,在整个操作系统 挂了时才可能丢数据,一般不会丢失超过1-2秒的更新。
  6. 事务提交时,立即写入磁盘文件(这里只是写入到系统内核缓冲区,但不立即刷新到磁盘,而是每隔1秒刷新到磁盘,同时更新数据和索引),
  7. 这种方案是不是性价比好一些,当然如何配置,决定于你对系统数据安全性的要求。

explain用法详解


  1. EXPLAIN tbl_name或:EXPLAIN [EXTENDED] SELECT select_options
  2. 前者可以得出一个表的字段结构等等,后者主要是给出相关的一些索引信息,而今天要讲述的重点是后者。

  • 举例



 

  • 各个属性的含义



  • id :select查询的序列号

    • select_type:select查询的类型,主要是区别普通查询和联合查询、子查询之类的复杂查询。

      1. a.SIMPLE:查询中不包含子查询或者UNION
      2. b.查询中若包含任何复杂的子部分,最外层查询则被标记为:PRIMARY
      3. c.在SELECTWHERE列表中包含了子查询,该子查询被标记为:SUBQUERY
      4. d.在FROM列表中包含的子查询被标记为:DERIVED(衍生)
      5. e.若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在 FROM子句的子查询中,外层SELECT将被标记为:DERIVED
      6. f.从UNION表获取结果的SELECT被标记为:UNION RESULT


    • table :输出的行所引用的表。


    • type :联合查询所使用的类型,表示MySQL在表中找到所需行的方式,又称“访问类型”


  1. type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:
  2. system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
  3. 一般来说,得保证查询至少达到range级别,最好能达到ref

  1. ALL: 扫描全表
  2. index: 扫描全部索引树
  3. range: 扫描部分索引,索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行,常见于between、<、>等的查询
  4. ref: 非唯一性索引扫描,返回匹配某个单独值的所有行。常见于使用非唯一索引即唯一索引的非唯一前缀进行的查找
  5. eq_ref唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
  6. const, system: MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。
  7. 如将主键置于where列表中,MySQL就能将该查询转换为一个常量。systemconst类型的特例,当查询的表只有一行的情况下, 使用system
  8. NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引。


如下所示:



  • possible_keys:
    1. 指出MySQL能使用哪个索引在该表中找到行。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用。
    2. 如果是空的,没有相关的索引。这时要提高性能,可通过检验WHERE子句,看是否引用某些字段,或者检查字段不是适合索引。
 

  • key :显示MySQL实际决定使用的键。如果没有索引被选择,键是NULL。
    1. key_len:显示MySQL决定使用的键长度。表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。如果键是NULL,长度就是NULL
    2. 文档提示特别注意这个值可以得出一个多重主键里mysql实际使用了哪一部分。
    3. 注:key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
    4. ref:显示哪个字段或常数与key一起被使用。

 

  • rows:这个数表示mysql要遍历多少数据才能找到。
    1. 表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数,在innodb上可能是不准确的。

 

  • Extra:包含不适合在其他列中显示但十分重要的额外信息。
    1. Only index,这意味着信息只用索引树中的信息检索出的,这比扫描整个表要快。
    2. using where是使用上了where限制,表示MySQL服务器在存储引擎受到记录后进行“后过滤”(Post-filter),
    3. 如果查询未能使用索引,Using where的作用只是提醒我们MySQL将用where子句来过滤结果集。
    4. impossible where 表示用不着where,一般就是没查出来啥。
    5. Using filesortMySQL中无法利用索引完成的排序操作称为“文件排序”)当我们试图对一个没有索引的字段进行排序时,就是filesoft
    6. 它跟文件没有任何关系,实际上是内部的一个快速排序。
    7. Using temporary(表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询),使用filesorttemporary的话会很吃力,
    8. WHEREORDER BY的索引经常无法兼顾,如果按照WHERE来确定索引,那么在ORDER BY时,
    9. 就必然会引起Using filesort,这就要看是先过滤再排序划算,还是先排序再过滤划算。

最后,再看一个查询计划的例子:


  1. 第一行:id列为1,表示第一个selectselect_type列的primary表示该查询为外层查询,
  2. table列被标记为<derived3>,表示查询结果来自一个衍生表,其中3代表该查询衍生自第三个select查询,即id3select。[select d1.name......]
  3. 第二行:id3,表示该查询的执行次序为243),是整个查询中第三个select的一部分。
  4. 因查询包含在from中,所以为derived。[select id,name from t1 where other_column='']
  5. 第三行:select列表中的子查询,select_typesubquery,为整个查询中的第二个select。[select id from t3]
  6. 第四行:select_typeunion,说明第四个selectunion里的第二个select,最先执行。[select name,id from t2]
  7. 第五行:代表从union的临时表中读取行的阶段,table列的<union1,4>表示用第一个和第四个select的结果进行union操作。[两个结果union操作]

关于MySQL执行计划的局限性:

  1. EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
  2. EXPLAIN不考虑各种Cache
  3. EXPLAIN不能显示MySQL在执行查询时所作的优化工作
  4. 部分统计信息是估算的,并非精确值
  5. EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看。


备注:

  1. filesort是通过相应的排序算法,将取得的数据在内存中进行排序。
  2. MySQL需要将数据在内存中进行排序,所使用的内存区域也就是我们通过sort_buffer_size 系统变量所设置的排序区。
  3. 这个排序区是每个Thread 独享的,所以说可能在同一时刻在MySQL 中可能存在多个 sort buffer 内存区域。


在MySQL中filesort 的实现算法实际上是有两种:

  1. 双路排序:是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后在sort buffer 中进行排序。
  2. 单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序。
  1. MySQL4.1版本之前只有第一种排序算法双路排序,第二种算法是从MySQL4.1开始的改进算法,
  2. 主要目的是为了减少第一次算法中需要两次访问表数据的IO操作,将两次变成了一次,但相应也会耗用更多的sortbuffer 空间。当然,MySQL4.1开始的以后所有版本同时也支持第一种算法。
  3. MySQL主要通过比较我们所设定的系统参数 max_length_for_sort_data的大小和Query 语句所取出的字段类型大小总和来判定需要使用哪一种排序算法
  4. 如果 max_length_for_sort_data更大,则使用第二种优化后的算法,反之使用第一种算法。
  5. 所以如果希望 ORDER BY 操作的效率尽可能的高,一定要注意max_length_for_sort_data 参数的设置。
  6. 如果filesort过程中,由于排序缓存的大小不够大,那么就可能会导致临时表的使用。
  7. max_length_for_sort_data的默认值是1024

参考来源: http://blog.csdn.net/xifeijian/article/details/19773795