MySQL EXPLAIN的輸出信息

MySQL EXPLAIN的輸出信息mysql

表結構
drop table article;
drop table user;
-- 最終的兩個表的定義,authorId上沒有任何索引(不是外鍵,也沒有索引)
create table article(
id int auto_increment primary key,
title varchar(255) not null,
shortName varchar(255) not null,
authorId int not null,
createTime datetime not null,
state int  not null,
totalView int default null,
unique index idx_short_name_title (title,shortName)
);
create table user (
id int auto_increment primary key,
name varchar(255) not null,
sex bit default 0,
email varchar(50) not null, 
address varchar(255) default null,
unique index idx_email (email),
index idx_name (name)
);
insert into article (title,shortName,authorId,createTime,state,totalView) 
values ('hello world','hello-world-0',1,'2015-10-11 08:08:08',1,10),
('hello world','hello-world-1',1,'2015-10-11 08:08:08',2,10),
('hello world','hello-world-2',2,'2015-10-11 08:08:08',3,10),
('hello world','hello-world-3',3,'2015-10-11 08:08:08',4,10),
('hello world','hello-world-4',3,'2015-10-11 08:08:08',5,10);
insert into user (name,sex,email,address) values('lyx',0,'000@gmail.com','bj'),
('lyx',0,'111@gmail.com','bj'),
('lyx-0',0,'222@gmail.com','bj'),
('lyx-1',0,'333@gmail.com','bj');
====
alter table article add constraint fk_author_id foreign key (authorId) references user(id);
alter table article drop foreign key fk_author_id;
alter table article drop index fk_author_id;
alter table article add index idx_author_id (authorId);
alter table article drop index idx_author_id;
show create table article;
====

基本用法

explain article;sql

explain select * from article a where a.author_id in (select author_id from user);服務器

第一個至關於desc表結構。性能

第二個表示select查詢語句的查詢計劃優化

 

select_type 列

SUBQUERY

> explain select (select 1 from article limit 1) from user

******************** 1. row *********************
           id: 1
  select_type: PRIMARY
        table: user
         type: index
possible_keys: 
          key: idx_email
      key_len: 52
          ref: 
         rows: 4
        Extra: Using index
******************** 2. row *********************
           id: 2
  select_type: SUBQUERY
        table: article
         type: index
possible_keys: 
          key: idx_short_name_title
      key_len: 514
          ref: 
         rows: 5
        Extra: Using index
2 rows in set

包含在select列表中的子查詢的select(換句話說,不在form子句中)標記爲SUBQUERY。this

DEPENDENT SUBQUERY

> explain 
select * from article a where exists (select * from user u where a.authorId = u.id)

******************** 1. row *********************
           id: 1
  select_type: PRIMARY
        table: a
         type: ALL
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 5
        Extra: Using where
******************** 2. row *********************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: u
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: test.a.authorId
         rows: 1
        Extra: Using index
2 rows in set

DERIVED

> explain select max(id) from (select * from article) a

******************** 1. row *********************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 5
        Extra: 
******************** 2. row *********************
           id: 2
  select_type: DERIVED
        table: article
         type: ALL
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 5
        Extra: 
2 rows in set

DERIVED值用來表示包含在from子句的子查詢中的select,mysql會遞歸併將結果防盜一個臨時表中。服務器內部稱其爲「派生表」,由於該表是從子查詢中派生出來的。spa

UNION && UNION RESULT

> explain select id , title from article a where a.id = 1 union select id ,title from article b where b.id = 2

******************** 1. row *********************
           id: 1
  select_type: PRIMARY
        table: a
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: 
******************** 2. row *********************
           id: 2
  select_type: UNION
        table: b
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: 
******************** 3. row *********************
           id: 
  select_type: UNION RESULT
        table: <union1,2>
         type: ALL
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 
        Extra: Using temporary
3 rows in set

 

type 列

mysql用戶手冊上說這一列顯示了「關聯類型」,但咱們認爲更準確的說法是訪問類型——換言之就是mysql決定如何查找表中的行。下面是最重的訪問數據行的方法,依次從最差到最優。code

ALL

這就是人們所稱的全表掃描,一般意味着mysql必須掃描整張表,從頭至尾,去找到須要的行。(這裏也有個例外,例如在查詢裏使用了LIMIT,或者在Extra列中顯示using distinct/not exists)。orm

好比,排序

> explain
select * from article

******************** 1. row *********************
           id: 1
  select_type: SIMPLE
        table: article
         type: ALL
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 5
        Extra: 
1 rows in set

index

這個跟全表掃描同樣,只是mysql掃描表的時候按照索引次序進行而不是行。它的主要優勢是避免了排序;最大的缺點時要承擔按索引次序讀取整個表的開銷。這一般意味着如是按照隨機次序訪問行,開銷將會很是大。

若是在Extra列中看到了using index,說明mysql正在使用覆蓋索引,他只是掃描索引的數據,而不是按索引次序的每一行。他比按照索引次序全表掃描的開銷要少不少。

> explain
select id , title from article

******************** 1. row *********************
           id: 1
  select_type: SIMPLE
        table: article
         type: index
possible_keys: 
          key: idx_short_name_title
      key_len: 514
          ref: 
         rows: 5
        Extra: Using index
1 rows in set

range

mysql5.6手冊解釋:

Only rows that are in a given range are retrieved, using an index to select the rows. The key column in the output row indicates which index is used. The key_len contains the longest key part that was used. The ref column isNULL for this type.

range can be used when a key column is compared to a constant using any of the =, <>, >, >=, <, <=, IS NULL,<=>, BETWEEN, or IN() operators.

範圍掃描就是一個有限制的索引掃描,它開始於索引裏的某一點,返回匹配這個值域的行。這比全索引掃描好一些,由於它用不着遍歷所有索引。顯而易見的範圍掃描是帶有between或在where子句裏帶有>的查詢。

當mysql使用索引去查找一系列值時,例如 IN() 或 OR列表,也會顯示爲範圍掃描。然而這二者實際上是至關不一樣的訪問類型,在性能上有重要的差別。

> explain 
select * from article where id > 2

******************** 1. row *********************
           id: 1
  select_type: SIMPLE
        table: article
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: 
         rows: 3
        Extra: Using where
1 rows in set

要注意並非全部的範圍查詢當執行查詢計劃時出現type=range,以下面的sql

> explain 
select * from article a where a.totalView >2

******************** 1. row *********************
           id: 1
  select_type: SIMPLE
        table: a
         type: ALL
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 5
        Extra: Using where
1 rows in set

這是由於totalView列上沒有創建索引。

ref 列

這是一種索引訪問(有時也叫作索引查找),它返回全部匹配某個單個值的行。然而,它可能會找到多個符合條件的行,所以,它是查找和掃描的混合體。此類索引訪問只有當使用非惟一性索引或者惟一性索引的非惟一性前綴時纔會發生。把它叫作ref是由於要跟某個參考值相比較。這個參考值或者是一個常數,或者是來自多表查詢前一個表裏的結果值。

ref_or_null是ref之上的一個遍體,它意味着mysql必須在初次查找的結果裏進行第二次查找以找出NULL條目。

首先咱們給authorId列建上索引,

alter table article add index idx_author_id (authorId);

> explain
select * from article where authorId = 1

******************** 1. row *********************
           id: 1
  select_type: SIMPLE
        table: article
         type: ref
possible_keys: idx_author_id
          key: idx_author_id
      key_len: 4
          ref: const
         rows: 2
        Extra: 
1 rows in set

再看一個示例,

> explain
select * from article a , user u where a.authorId = u.id and a.authorId = 1

******************** 1. row *********************
           id: 1
  select_type: SIMPLE
        table: u
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: 
******************** 2. row *********************
           id: 1
  select_type: SIMPLE
        table: a
         type: ref
possible_keys: idx_author_id
          key: idx_author_id
      key_len: 4
          ref: const
         rows: 2
        Extra: 
2 rows in set

下面着三個sql的訪問數據的方式type都是ref,

explain
select * from article a , user u where a.authorId = u.id and a.authorId = 1;

explain
select * from article a inner join user u on a.authorId = u.id and a.authorId = 1;

explain
select * from article a inner join user u on a.authorId = u.id where a.authorId = 1;

eq_ref

使用這種索引查找,mysql知道最多隻返回一條符合條件的記錄。這種訪問方式能夠在mysql使用主鍵活着惟一索引查找時看到,它會將他們與某個參考值作比較。mysql對於這類訪問類型的優化作的很是好,由於它知道無須估計匹配行的範圍或在找到匹配行後再繼續查找。

基於上面的表結構中,authorId列上沒有索引,咱們要給他創建一個惟一索引

alter table article add unique index idx_author_id (authorId);

> explain 
select * from article a left join user u on a.authorId = u.id 

******************** 1. row *********************
           id: 1
  select_type: SIMPLE
        table: a
         type: ALL
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 1
        Extra: 
******************** 2. row *********************
           id: 1
  select_type: SIMPLE
        table: u
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: test.a.authorId
         rows: 1
        Extra: 
2 rows in set

再看一個使用exists子查詢的示例,先把上面創建的索引刪掉

alter table article drop index idx_author_id;

> explain 
select * from article a where exists (select * from user u where a.authorId = u.id)

******************** 1. row *********************
           id: 1
  select_type: PRIMARY
        table: a
         type: ALL
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 5
        Extra: Using where
******************** 2. row *********************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: u
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: test.a.authorId
         rows: 1
        Extra: Using index
2 rows in set

訪問數據行的類型也是eq_ref。exists子查詢的做用就是判斷前面查詢出來的數據行在子查詢中存在不存在,若是存在就返回true。因此只要肯定有一條記錄存在就行。

type const && type system

當mysql能對查詢的某部分進行優化並將其轉換爲一個常量時,他就會使用這些訪問類型。舉例來講,若是你經過將某一行的主鍵放入where子句中裏的方式來選取此行的主鍵,mysql就能將這個查詢轉換爲一個常量。

> explain 
select * from (select * from article a where a.id=1) temp_a inner join user u on temp_a.authorId = u.id

******************** 1. row *********************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: system
possible_keys: 
          key: 
      key_len: 
          ref: 
         rows: 1
        Extra: 
******************** 2. row *********************
           id: 1
  select_type: PRIMARY
        table: u
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: 
******************** 3. row *********************
           id: 2
  select_type: DERIVED
        table: a
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: 
3 rows in set

 

Extra 列

放到下一篇文章來講。

============END============

相關文章
相關標籤/搜索