• MySQL----explain/trace


    如何使用慢查询快速定位执行慢的 SQL?

    慢查询可以帮我们找到执行慢的 SQL

    • 查看慢查询是否已经开启
    show variables like '%slow_query_log';
    
    • 我们能看到slow_query_log=OFF,也就是说慢查询日志此时是关上的。我们可以把慢查询日志打开,注意设置变量值的时候需要使用 global,否则会报错:
    set global slow_query_log='ON';
    
    • 然后我们再来查看下慢查询日志是否开启,以及慢查询日志文件的位置
    show variables like '%slow_query_log%';
    

      

    • 如果我们想把时间缩短,比如设置为 3 秒,可以这样设置:
    set global long_query_time = 3;
    

      

    mysqldumpslow 工具

    MySQL 自带的 mysqldumpslow 工具统计慢查询日志(这个工具是个 Perl 脚本,你需要先安装好 Perl)

    perl下载:http://www.activestate.com/activeperl/downloads

    mysqldumpslow 命令的具体参数如下:

    -s:采用 order 排序的方式,排序方式可以有以下几种。分别是 c(访问次数)、t(查询时间)、l(锁定时间)、r(返回记录)、ac(平均查询次数)、al(平均锁定时间)、ar(平均返回记录数)和 at(平均查询时间)。其中 at 为默认排序方式。
    -t:返回前 N 条数据 。
    -g:后面可以是正则表达式,对大小写不敏感。

     

     explain:

     

    id

    select 执行顺序

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

    2. id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行

    select_type

    (1) SIMPLE(简单SELECT,不使用UNION或子查询等)

    (2) PRIMARY(复杂查询最外面的select)

    (3) UNION(UNION中的第二个或后面的SELECT语句)

    (4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)

    (5) UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select)

    (6) SUBQUERY(包含在 select 中的子查询(不在 from 子句中),就是select  (select * from ) from xx,中第二个select,子查询from前面的查询)

    (7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询)

    (8) DERIVED(派生表的SELECT, FROM后面的子查询)

    (9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)

    table

    显示这一步所访问数据库中表名称

    type

    ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)

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

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

    range:只检索给定范围的行,使用一个索引来选择行

    ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

    eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件

    const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system

    NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

    possible_keys

    该表可以利用的索引

    示例

    #关闭mysql5.7新特性对衍生表的合并优化

    set session optimizer_switch='derived_merge=off'; //设置on恢复
    

    创建表和插入数据

    drop table if exists actor;
    create table actor(
        id int(11) not null,
        name varchar(20) default null,
        update_time datetime default null,
        primary key (id)
    )ENGINE=InnoDB default charset utf8;
    drop table if exists film;
    create table film(
        id int(11) not null auto_increment,
        name varchar(20) default null,
        primary key (id),
        key idx_name (name)
    )ENGINE=InnoDB default charset utf8;
    DROP TABLE IF EXISTs film_actor;
    CREATE TABLE film_actor(
        id int(11) NOT NULL,
        film_id int(11)NOT NULL,
        actor_id int(11) NOT NULL,
        remark varchar(255) DEFAULT NULL,
        PRIMARY KEY (id),
        KEY idx_film_actor_id(film_id,actor_id)
    )ENGINE=InnoDB default charset utf8;
    insert into actor(id, name, update_time) VALUES (1,'小明',current_date);
    insert into actor(id, name, update_time) VALUES (2,'小红',current_date);
    insert into actor(id, name, update_time) VALUES (3,'小花',current_date);
    insert into film(name) values ('film1'),('film2'),('film2');
    INSERT INTO film_actor(id,film_id,actor_id) values (2,1,2),(3,2,1),(1,1,1);

    select_type

    primary、subquery 和 derived 类型

    explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;
    

    select_type

    union

    explain select 1 union all select 1;
    

    type

    sytem,const

    system是const的特例,表里只有一条元组匹配时为 system

    explain extended select * from (select * from film where id = 1) tmp;
    

    type

    eq_ref,关联表才会出现这种连接

    primary key 或 unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录。这可能是在 const 之外最好的联接类型了,简单的 select 查询不会出现这种 type。

    explain select * from film_actor left join film on film_actor.film_id = film.id;
    

    • film表用film.id和其他表关联,film_id是唯一的(primary key),所以type是eq_ref
    • 如果film_actor.film_id = film.name;那么type就是index,因为name不唯一,就要进行索引扫描

    type

    ref

    相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。

    explain select * from film where name = 'film1';
    

    index

    range

    范围扫描通常出现在 in(), between ,> ,<, >= 等操作中。使用一个索引来检索给定范围的行。

    explain select * from actor where id > 1;
    

    type

    index

    扫描全表索引,这通常比ALL快一些。

    explain select * from film; 

    type

    ALL

    即全表扫描,意味着mysql需要从头到尾去查找所需要的行。通常情况下这需要增加索引来进行优化了

    explain select * from actor;
    

    possible_keys

    explain 时可能出现 possible_keys 有列,而 key 显示 NULL 的情况,这种情况是因为表中数据不多,mysql认为索引对此查询帮助不大,选择了全表查询。 如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查 where 子句看是否可以创造一个适当的索引来提高查询性能,然后用 explain 查看效果。

    key

    这一列显示mysql实际采用哪个索引来优化对该表的访问。如果没有使用索引,则该列是 NULL。如果想强制mysql使用或忽视possible_keys列中的索引,在查询中使用 force index、ignore index。

    key_len

    这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。

    char(n):n字节长度
    varchar(n):2字节存储字符串长度,如果是utf-8,则长度 3n+2
    tinyint:1字节
    smallint:2字节
    int:4字节
    bigint:8字节
    date:3字节
    timestamp:4字节
    datetime:8字节

    如果字段允许为 NULL,需要1字节记录是否为 NULL

    索引最大长度是768字节,当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。

    Extra

    Using index

    使用覆盖索引,select中的字段都在索引中

    Extra

    Using where

    查询的列未被索引覆盖,where中的字段不在索引中

    Extra

    Using index condition

    查询的列不完全被索引覆盖,where条件中是一个前导列的范围;

    explain select * from film_actor where film_id > 1;
    

    Extra

    Using temporary

    mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。

    explain select distinct name from actor;
    

     如果将distict后面的name建立了索引

    Extra

    Using filesort

    将用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。这种情况下一般也是要考虑使用索引来优化的。

    explain select * from actor order by name;
    

    如果将order by后面的字段加上索引

     trace:

  • 相关阅读:
    Linux菜鸟级重点
    在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误
    搭建PHP开发环境
    Struts+Hibernate+Spring实现用户登录功能
    Struts2整合Hibernate3实现用户登录功能
    决战JS(二)
    决战JS
    lightoj-1098
    lightoj-1072
    lightoj-1094 Farthest Nodes in a Tree(求树的直径)
  • 原文地址:https://www.cnblogs.com/yanxiaoge/p/13637524.html
Copyright © 2020-2023  润新知