zoukankan      html  css  js  c++  java
  • [转]细说MySQL Explain和Optimizer Trace简介

    在开发过程中,对每个上线的SQL查询指纹(query figerprint)的质量都应有估算;而估算DB查询质量最直接的方法,就是分析其查询执行计划( Query Execution Plan ,即QEP)。
    MySQL数据库,通过Explain指令查看SELECT(5.6.3+版本开始支持update/delete/insert等),下图为sakila.actor的表结构和一个主建过滤查询的执行计划。
    explain_1
    本文细说从以下三个方面:
    1.如何读取EXPLAIN的输出结果
    2.简介MySQL5.6的 EXPLAIN FORMAT = JSON和MySQL Workbench的Visual Explain
    3.简介MySQL的CBO和Optimizer Trace


    如何读取EXPLAIN的输出结果

    EXPLAIN的输出一般12个字段(其中partitions和filtered 5.5版本普通模式下没有),会对重要的字段内容进行分析说明
    explain_1
    本节详细分析,每个字段的含义和使用。

    id字段

    表示SELECT查询标识符,用于标识执行顺序,基本是数字;
    执行顺序原则:id数据值大的优先执行,id值相同的从上往下顺序执行; 上图id值都为1,故SQ先执行actor表的查询

    select_type字段

    表示select子句的类型,常值有:
    SIMPLE: 简单查询,查询子句不包含UNION或子查询
    PRIMARY:最外层的SELECT子句
    UNION: UNION子句右侧的SELECT子句
    SUBQUERY: 子查询中第一个SELECT
    DERIVED: 衍生表的SELECT子句

    table字段

    表示查询涉及的表或衍生表; 图2中:第一行操作的actor表的查询,第二行操作是file_actor表的查询;

    partitions字段:

    针对MySQL内置分区表,表示当前使用了哪些子分区;用于确认查询对分区的过滤效率

    type字段[重要]

    表示查询的access type,表示查询是否为”全表扫描“,”索引扫描“等
    常见以下几种类型,查询效率由最差到最好
    all<index<range ~ index_merge< ref<eq_ref<const<system(效率理论从最差到最好)
    详细说明每种常见type表示的含义

    • 5.1 ALL 表示”全表扫描”(full table scan), 性能是最差的几种查询之一,如果查询的表比较大,且查询频次高,对MySQL数据库有致命的性能影响。
      见下图:因last_update字段没有索引,帮整体是全表扫描, 扫描rows 200条
      explain_1
    • 5.2 index 表示“全索引扫描”(full index scan),其类型和ALL较类似,性能也是比较差; 和ALL区别在于只对索引树进行扫描,但索引没有起到过滤作用。
      explain_1
    • 5.3 range 表示“索引范围扫描”, 通过索引字段范围获取表中部分数据记录; 常常用于in,>,< between等操作,查询效率一般不错。 下图rows只扫描了4行数据,就获取到指定数据
      explain_1
    • 5.4 index_merge MySQL查询优化器发现查询可以同时使用多个索引查询结果集进行并集或交集的情况,就会使用index_merge type。
      此时key字段有两个或多个索引, key_len/rows都分别有两个数值; 如果是并集操作”Using intersect”, 往往通过两个索引的字段,合并为一个索引,避免index_merge查询
      下图中两个SQL一个是AND/OR, Using intersect 和Using union 分别表示使用两个索引后的交集和并集
      explain_1
    • 5.5 ref 针对于非唯一或主键索引,或使用二者”最左部分字段”索引的等值查询或多表join,查询效率由这个值返回的行数多少决定
    • 5.6 eq_ref 使用于多表的join时,被驱动表的过滤字段是主键或唯一索引,查询效率很好
    • 5.7 const 针对主键或唯一索引的等值查询扫描,最多只返回一行数据
    • 5.8 system: 是一种特殊const类型,被查询表中有且只有一条数据

      possible_keys字段

      表示MySQL查询优化器发现当前查询可能被使用地索引,但不一定能会利用,如果possible_key的列举的索引越多,往往说明索引创建不合理,查询效率不是最高效;
      因为优化器会分析尽可能多的索引,评估哪个索引的“成本”消耗局部最低,这个评估过程消耗时间和资源的。

      key 字段[重要]

      表示查询优化器真正使用的索引(可能多个,如前index_merge), 如果是索引覆盖,那么索引不会在possible_keys中出现的; 注意:对于组合索引,查询可能只使用其部分字段,详细见下面key_len计算分析

      key_len字段[重要]

      表示查询优化器使用了索引的字节数,可以评估组合索引是否完全被使用,或只有最左部分字段使用
      key_len字节的计算规则:
    • 字符串:char(n) - n字节, varchar(n)- n字节 + 2字节(变长), , 多字节charset * [1~4]字节(utf8为3字节,utf8mb4为4字节计算)
    • 数值类型: TINYINT-1字节,SMALLINT-2字节, MEDIUMINT-3字节, INT-4字节,BIGINT-8字节
    • 时间类型:DATE-3字节, TIMESTAMP-4字节, DATETIME-8字节
    • 字段属性:NULL属性+ 1字节
      计算demo:
      下图两个SQL使用相同的索引,但索引的效果和key_len却分别是9字节和119字节
      SQL1 key_len计算: pay_user_id字段8字节(bigint not null) + product_type字段 1个字节 = 共9个字节, 说明SQL1只使用了idx_userid组合索引的前2个字段,product_id字段未使用,过滤性不太好。
      SQL key_len计算: 前两字段9字节+ product_id字段110字节 ( varchar(36) utf8字符集和2字节变长, 36*3+2为110字节) = 9 + 110=119字节, SQL2使用了前三个字段,过滤性较好
      explain_1

      rows 字段[重要]

      MySQL查询优化器根据统计信息,估算SQL要查找到结果集需要扫描读取的数据行数; 这个值非常直观显示SQL的效率好坏,原则rows越少越好。
      后文会计划的优化器的cost估算时,ROW_EVALUATE_COST就是扫描1行数据,算0.2

    Extra字段[重要]

    MySQL执行计划很多额外的信息在Extra字段显示,常见的有以下几种内容

    • 10.1 Using filesort
      MySQL需额外的排序操作,不能通过索引顺序达到排序效果;又叫”文件排序“,易错误理论为排序结果过大,内存中不够需写磁盘文件排序。
      一般有filesort,都建议优化去掉,CPU资源消耗大。 下图last_update排序,但此字段无索引,故需filesort
      explain_1
    • 10.2 Using index
      ”覆盖索引扫描“,表示查询在索引树中就可查找所需数据,不用回表数据文件(回表操作),往往说明性能不错
    • 10.3 Using temporary
      查询有使用临时表,一般出现于排序,分组和多表join的情况,查询效率不高,建议优化

    简介EXPLAIN FORMAT=JSON 和 MySQL Workbench的Visual Explain

    EXPLAIN FORMAT=JSON

    从MySQL5.6,支持JSON格式的输出;输出的结果信息更详细,针对复杂查询的执行计划结构顺序更加清晰
    explain format=json select f.film_id, f.title, c.name from film f inner join film_category fc on f.film_id=fc.film_id inner join category c on fc.category_id = c.category_id where f.title like ‘B%’;

    explain_1

    MySQL Workbench的Visual Explain

    MySQL Workbench的Visual Explain
    执行计划的读取是:从左往右,从下往上
    explain_1

    简介MySQL的CBO和Optimizer Trace

    从MySQL5.6版本开始,可支持把MySQL查询执行计划树打印出来,对DBA深入分析SQL执行计划,COST成本都非常有用,打印的内部信息比较全面;
    功能支持动态开关,因为对性能有20%左右影响,只建议分析问题时,临时开启
    1 使用方式 set session optimizer_trace= “enabled=on”; 然后执行你要分析的SQL, 再执行SELECT trace FROM information_schema.OPTIMIZER_TRACE;就可查看SQL的Optimizer Trace信息
    DEMO:
    set session optimizer_trace= “enabled=on”;
    select from actor ;
    SELECT trace FROM information_schema.OPTIMIZER_TRACEG
    使用场景举例:计算评估查询的“成本” CBO
    MySQL优化器通过计算每种可能计划的“成本”,最终选择“成本”最小的作为执行计划。
    MySQL查询优化器都是Cost Model包含两个模型IO和CPU
    以下为Table scan的情况的IO计算公式,用于验证 Optimizer Trace的cost-info是否一致
    IO Cost : 读取的table/index的页个数 
    O_BLOCK_READ_COST #其中O_BLOCK_READ_COST常量为1
    CPU Cost: 读取行数 rows ROW_EVALUATE_COST #其中ROW_EVALUATE_COST常量为0.2
    计算 select 
    from actor 这个查询的执行计划cost-info:
    通过 select from mysql.innodb_index_stats where table_name =’actor’ and stat_name=’size’; 获取这次表扫描primary只有1个page,rows为200行
    总体cost = io-cost+cpu-cost = 1 pages 
    O_BLOCK_READ_COST + 200 rows ROW_EVALUATE_COST= 11 + 200 * 0.2 = 41
    和图中”best_access_path”中cost值41相匹配。(当然MySQL在Range,join等复杂SQL的查询分析,相当复杂,这里只是举例说明trace输出信息的强大)
    输出结果如下图:
    explain_1

     
  • 相关阅读:
    CF261E Maxim and Calculator
    USACO Section 2.1
    码工新人的成长升职之路~
    Skip level 1 on 1
    有效利用1 on 1
    [职场感言] 入职一年总结
    职场新人建议
    L1 正则为什么会使参数偏向稀疏
    Inception网络
    ResNet
  • 原文地址:https://www.cnblogs.com/lurenjiashuo/p/mysql-explain.html
Copyright © 2011-2022 走看看