mysql explain type連接類型示例

對于mysql執行計劃的獲取,我們可以通過explain方式來查看,explain方式看似簡單,實際上包含的內容很多,尤其是輸出結果中的type類型列。理解這些不同的類型,對于我們SQL優化舉足輕重,本文僅描述explian輸出結果中的type列,同時給出其演示。有關explian輸出的全描述,可以參考:MySQL EXPLAIN SQL 輸出信息描述

一、EXPLAIN 語句中type列的值

type:  ????連接類型  ????system??????????表只有一行????const???????????表最多只有一行匹配,通用用于主鍵或者唯一索引比較時  ????eq_ref??????????每次與之前的表合并行都只在該表讀取一行,這是除了system,const之外最好的一種,  ????????????????????特點是使用=,而且索引的所有部分都參與join且索引是主鍵或非空唯一鍵的索引  ????ref?????????????如果每次只匹配少數行,那就是比較好的一種,使用=或,可以是左覆蓋索引或非主鍵或非唯一鍵  ????fulltext????????全文搜索  ????ref_or_null?????與ref類似,但包括NULL  ????index_merge?????表示出現了索引合并優化(包括交集,并集以及交集之間的并集),但不包括跨表和全文索引。  ????????????????????這個比較復雜,目前的理解是合并單表的范圍索引掃描(如果成本估算比普通的range要更優的話)  ????unique_subquery?在in子查詢中,就是value?in?(select...)把形如“select?unique_key_column”的子查詢替換。  ????????????????????PS:所以不一定in子句中使用子查詢就是低效的!  ????index_subquery??同上,但把形如”select?non_unique_key_column“的子查詢替換  ????range???????????常數值的范圍????index???????????a.當查詢是索引覆蓋的,即所有數據均可從索引樹獲取的時候(Extra中有Using?Index);  ????????????????????b.以索引順序從索引中查找數據行的全表掃描(無?Using?Index);  ????????????????????c.如果Extra中Using?Index與Using?Where同時出現的話,則是利用索引查找鍵值的意思;  ????????????????????d.如單獨出現,則是用讀索引來代替讀行,但不用于查找  ????all?????????????全表掃描

二、連接類型部分示例

1、all--?環境描述  (root@localhost)?[sakila]&gt;?show?variables?like?'version';  +---------------+--------+  |?Variable_name?|?Value??|  +---------------+--------+  |?version???????|?5.6.26?|  +---------------+--------+  MySQL采取全表遍歷的方式來返回數據行,等同于Oracle的full?table?scan  (root@localhost)?[sakila]&gt;?explain?select?count(description)?from?film;  +----+-------------+-------+------+---------------+------+---------+------+------+-------+  |?id?|?select_type?|?table?|?type?|?possible_keys?|?key??|?key_len?|?ref??|?rows?|?Extra?|  +----+-------------+-------+------+---------------+------+---------+------+------+-------+  |??1?|?SIMPLE??????|?film??|?ALL??|?NULL??????????|?NULL?|?NULL????|?NULL?|?1000?|?NULL??|  +----+-------------+-------+------+---------------+------+---------+------+------+-------+  2、index  MySQL采取索引全掃描的方式來返回數據行,等同于Oracle的full?index?scan  (root@localhost)?[sakila]&gt;?explain?select?title?from?film?G  ***************************?1.?row?***************************???????????  id:?1??  select_type:?SIMPLE????????  table:?film?????????  type:?indexpossible_keys:?NULL  ??????????key:?idx_title??????  ??????????key_len:?767??????????  ??????????ref:?NULL?????????  ??????????rows:?1000????????  ??????????Extra:?Using?index1?row?in?set?(0.00?sec)    3、??range  索引范圍掃描,對索引的掃描開始于某一點,返回匹配值域的行,常見于between、等的查詢  等同于Oracle的index?range?scan  (root@localhost)?[sakila]&gt;?explain?select?*?from?payment?where?customer_id&gt;300?and?customer_id?explain?select?*?from?payment?where?customer_id?in?(200,300,400)G  ***************************?1.?row?***************************  ???????????id:?1  ??select_type:?SIMPLE????????  ??table:?payment?????????  ??type:?rangepossible_keys:?idx_fk_customer_id??????????  ??key:?idx_fk_customer_id??????  ??key_len:?2??????????  ??ref:?NULL?????????  ??rows:?86????????  ??Extra:?Using?index?condition1?row?in?set?(0.00?sec)    4、ref  非唯一性索引掃描或者,返回匹配某個單獨值的所有行。常見于使用非唯一索引即唯一索引的非唯一前綴進行的查找  (root@localhost)?[sakila]&gt;?explain?select?*?from?payment?where?customer_id=305G  ***************************?1.?row?***************************  ???????????id:?1  ??select_type:?SIMPLE????????  ??table:?payment?????????  ??type:?refpossible_keys:?idx_fk_customer_id??????????  ??key:?idx_fk_customer_id??????  ??key_len:?2??????????  ??ref:?const?????????  ??rows:?25????????  ??Extra:?1?row?in?set?(0.00?sec)    idx_fk_customer_id為表payment上的外鍵索引,且存在多個不不唯一的值,如下查詢  (root@localhost)?[sakila]&gt;?select?customer_id,count(*)?from?payment?group?by?customer_id  ????-&gt;?limit?2;  +-------------+----------+  |?customer_id?|?count(*)?|+-------------+----------+  |???????????1?|???????32?||???????????2?|???????27?|  +-------------+----------+--?下面是非唯一前綴索引使用ref的示例  (root@localhost)?[sakila]&gt;?create?index?idx_fisrt_last_name?on?customer(first_name,last_name);  Query?OK,?599?rows?affected?(0.09?sec)  Records:?599??Duplicates:?0??Warnings:?0(root@localhost)?[sakila]&gt;?select?first_name,count(*)?from?customer?group?by?first_name?  ????-&gt;?having?count(*)&gt;1?limit?2;  +------------+----------+|?first_name?|?count(*)?|  +------------+----------+|?JAMIE??????|????????2?||?JESSIE?????|????????2?|  +------------+----------+2?rows?in?set?(0.00?sec)    (root@localhost)?[sakila]&gt;?explain?select?first_name?from?customer?where?first_name='JESSIE'G  ***************************?1.?row?***************************???????????  id:?1??select_type:?SIMPLE????????  table:?customer?????????  type:?refpossible_keys:?idx_fisrt_last_name??????????  key:?idx_fisrt_last_name??????  key_len:?137??????????  ref:?const?????????  rows:?2????????  Extra:?Using?where;?Using?index1?row?in?set?(0.00?sec)    (root@localhost)?[sakila]&gt;?alter?table?customer?drop?index?idx_fisrt_last_name;  Query?OK,?599?rows?affected?(0.03?sec)  Records:?599??Duplicates:?0??Warnings:?0--下面演示出現在join是ref的示例  (root@localhost)?[sakila]&gt;?explain?select?b.*,a.*?from?payment?a?inner?join????-&gt;?customer?b?on?a.customer_id=b.customer_idG  ***************************?1.?row?***************************???????????  id:?1??  select_type:?SIMPLE????????  table:?b?????????  type:?ALLpossible_keys:?PRIMARY  ??????????key:?NULL  ??????key_len:?NULL??????????  ??????ref:?NULL?????????  ??????rows:?599????????  ??????Extra:?NULL  ??????***************************?2.?row?***************************???????????  ??????id:?1??  ??????select_type:?SIMPLE????????  ??????table:?a?????????  ??????type:?refpossible_keys:?idx_fk_customer_id??????????  ??????key:?idx_fk_customer_id??????  ??????key_len:?2??????????  ??????ref:?sakila.b.customer_id?????????  ??????rows:?13????????  ??????Extra:?NULL2?rows?in?set?(0.01?sec)    5、eq_ref  類似于ref,其差別在于使用的索引為唯一索引,對于每個索引鍵值,表中只有一條記錄與之匹配。  多見于主鍵掃描或者索引唯一掃描。  (root@localhost)?[sakila]&gt;?explain?select?*?from?film?a?join?film_text?b?  ????-&gt;?on?a.film_id=b.film_id;  +----+-------------+-------+--------+---------------+---------+---------+------------------+------+-------------+  |?id?|?select_type?|?table?|?type???|?possible_keys?|?key?????|?key_len?|?ref?????????|?rows?|?Extra???????|  +----+-------------+-------+--------+---------------+---------+---------+------------------+------+-------------+  |??1?|?SIMPLE??????|?b?????|?ALL????|?PRIMARY???????|?NULL????|?NULL????|?NULL????|?1000?|?NULL????|  |??1?|?SIMPLE??????|?a?????|?eq_ref?|?PRIMARY???????|?PRIMARY?|?2???????|?sakila.b.film_id?|????1?|?Using?where?|  +----+-------------+-------+--------+---------------+---------+---------+------------------+------+-------------+  (root@localhost)?[sakila]&gt;?explain?select?title?from?film?where?film_id=5;  +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+  |?id?|?select_type?|?table?|?type??|?possible_keys?|?key?????|?key_len?|?ref???|?rows?|?Extra?|  +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+|??1?|?SIMPLE??????  |?film??|?const?|?PRIMAR???|?PRIMARY?|?2???????|?const?|????1?|?NULL??|  +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+6、const、system:  當MySQL對查詢某部分進行優化,這個匹配的行的其他列值可以轉換為一個常量來處理。  如將主鍵或者唯一索引置于where列表中,MySQL就能將該查詢轉換為一個常量  (root@localhost)?[sakila]&gt;?create?table?t1(id?int,ename?varchar(20)?unique);  Query?OK,?0?rows?affected?(0.05?sec)    (root@localhost)?[sakila]&gt;?insert?into?t1?values(1,'robin'),(2,'jack'),(3,'henry');  Query?OK,?3?rows?affected?(0.00?sec)  Records:?3??Duplicates:?0??Warnings:?0    (root@localhost)?[sakila]&gt;?explain?select?*?from?(select?*?from?t1?where?ename='robin')x;  +----+-------------+------------+--------+---------------+-------+---------+-------+------+-------+  |?id?|?select_type?|?table??????|?type???|?possible_keys?|?key???|?key_len?|?ref???|?rows?|?Extra?|  +----+-------------+------------+--------+---------------+-------+---------+-------+------+-------+  |??1?|?PRIMARY?????|?<derived2>?|?system?|?NULL??????????|?NULL??|?NULL????|?NULL??|????1?|?NULL??|  |??2?|?DERIVED?????|?t1?????????|?const??|?ename?????????|?ename?|?23??????|?const?|????1?|?NULL??|  +----+-------------+------------+--------+---------------+-------+---------+-------+------+-------+  2?rows?in?set?(0.00?sec)    7、type=NULL  MySQL不用訪問表或者索引就可以直接得到結果  (root@localhost)?[sakila]&gt;?explain?select?sysdate();+----+-------------+-------+------+---------------+------+---------+------+------+----------------+  |?id?|?select_type?|?table?|?type?|?possible_keys?|?key??|?key_len?|?ref??|?rows?|?Extra??????????|  +----+-------------+-------+------+---------------+------+---------+------+------+----------------+  |??1?|?SIMPLE??????|?NULL??|?NULL?|?NULL??????????|?NULL?|?NULL????|?NULL?|?NULL?|?No?tables?used?|  +----+-------------+-------+------+---------------+------+---------+------+------+----------------+  1?row?in?set?(0.00?sec)</derived2>

對于MySQL執行計劃的獲取,我們可以通過explain方式來查看,explain方式看似簡單,實際上包含的內容很多,尤其是輸出結果中的type類型列。理解這些不同的類型,對于我們SQL優化舉足輕重,本文僅描述explian輸出結果中的type列,同時給出其演示。有關explian輸出的全描述,可以參考:MySQL EXPLAIN SQL 輸出信息描述

一、EXPLAIN 語句中type列的值

type:  ????連接類型  ????system??????????表只有一行????const???????????表最多只有一行匹配,通用用于主鍵或者唯一索引比較時  ????eq_ref??????????每次與之前的表合并行都只在該表讀取一行,這是除了system,const之外最好的一種,  ????????????????????特點是使用=,而且索引的所有部分都參與join且索引是主鍵或非空唯一鍵的索引  ????ref?????????????如果每次只匹配少數行,那就是比較好的一種,使用=或,可以是左覆蓋索引或非主鍵或非唯一鍵  ????fulltext????????全文搜索  ????ref_or_null?????與ref類似,但包括NULL  ????index_merge?????表示出現了索引合并優化(包括交集,并集以及交集之間的并集),但不包括跨表和全文索引。  ????????????????????這個比較復雜,目前的理解是合并單表的范圍索引掃描(如果成本估算比普通的range要更優的話)  ????unique_subquery?在in子查詢中,就是value?in?(select...)把形如“select?unique_key_column”的子查詢替換。  ????????????????????PS:所以不一定in子句中使用子查詢就是低效的!  ????index_subquery??同上,但把形如”select?non_unique_key_column“的子查詢替換  ????range???????????常數值的范圍????index???????????a.當查詢是索引覆蓋的,即所有數據均可從索引樹獲取的時候(Extra中有Using?Index);  ????????????????????b.以索引順序從索引中查找數據行的全表掃描(無?Using?Index);  ????????????????????c.如果Extra中Using?Index與Using?Where同時出現的話,則是利用索引查找鍵值的意思;  ????????????????????d.如單獨出現,則是用讀索引來代替讀行,但不用于查找  ????all?????????????全表掃描

二、連接類型部分示例

1、all--?環境描述  (root@localhost)?[sakila]&gt;?show?variables?like?'version';  +---------------+--------+  |?Variable_name?|?Value??|  +---------------+--------+  |?version???????|?5.6.26?|  +---------------+--------+MySQL采取全表遍歷的方式來返回數據行,等同于Oracle的full?table?scan  (root@localhost)?[sakila]&gt;?explain?select?count(description)?from?film;  +----+-------------+-------+------+---------------+------+---------+------+------+-------+  |?id?|?select_type?|?table?|?type?|?possible_keys?|?key??|?key_len?|?ref??|?rows?|?Extra?|  +----+-------------+-------+------+---------------+------+---------+------+------+-------+  |??1?|?SIMPLE??????|?film??|?ALL??|?NULL??????????|?NULL?|?NULL????|?NULL?|?1000?|?NULL??|  +----+-------------+-------+------+---------------+------+---------+------+------+-------+  2、index  MySQL采取索引全掃描的方式來返回數據行,等同于Oracle的full?index?scan  (root@localhost)?[sakila]&gt;?explain?select?title?from?film?G  ***************************?1.?row?***************************???????????  id:?1??  select_type:?SIMPLE????????  table:?film?????????  type:?indexpossible_keys:?NULL  ??????????key:?idx_title??????  ??????????key_len:?767??????????  ??????????ref:?NULL?????????  ??????????rows:?1000????????  ??????????Extra:?Using?index1?row?in?set?(0.00?sec)    3、??range  索引范圍掃描,對索引的掃描開始于某一點,返回匹配值域的行,常見于between、等的查詢  等同于Oracle的index?range?scan  (root@localhost)?[sakila]&gt;?explain?select?*?from?payment?where?customer_id&gt;300?and?customer_id?explain?select?*?from?payment?where?customer_id?in?(200,300,400)G  ***************************?1.?row?***************************  ???????????id:?1  ??select_type:?SIMPLE????????  ??table:?payment?????????  ??type:?rangepossible_keys:?idx_fk_customer_id??????????  ??key:?idx_fk_customer_id??????  ??key_len:?2??????????  ??ref:?NULL?????????  ??rows:?86????????  ??Extra:?Using?index?condition1?row?in?set?(0.00?sec)    4、ref  非唯一性索引掃描或者,返回匹配某個單獨值的所有行。常見于使用非唯一索引即唯一索引的非唯一前綴進行的查找  (root@localhost)?[sakila]&gt;?explain?select?*?from?payment?where?customer_id=305G  ***************************?1.?row?***************************  ???????????id:?1  ??select_type:?SIMPLE????????  ??table:?payment?????????  ??type:?refpossible_keys:?idx_fk_customer_id??????????  ??key:?idx_fk_customer_id??????  ??key_len:?2??????????  ??ref:?const?????????  ??rows:?25????????  ??Extra:?1?row?in?set?(0.00?sec)    idx_fk_customer_id為表payment上的外鍵索引,且存在多個不不唯一的值,如下查詢  (root@localhost)?[sakila]&gt;?select?customer_id,count(*)?from?payment?group?by?customer_id  ????-&gt;?limit?2;  +-------------+----------+  |?customer_id?|?count(*)?|+-------------+----------+  |???????????1?|???????32?||???????????2?|???????27?|  +-------------+----------+--?下面是非唯一前綴索引使用ref的示例  (root@localhost)?[sakila]&gt;?create?index?idx_fisrt_last_name?on?customer(first_name,last_name);  Query?OK,?599?rows?affected?(0.09?sec)  Records:?599??Duplicates:?0??Warnings:?0(root@localhost)?[sakila]&gt;?select?first_name,count(*)?from?customer?group?by?first_name?  ????-&gt;?having?count(*)&gt;1?limit?2;  +------------+----------+|?first_name?|?count(*)?|  +------------+----------+|?JAMIE??????|????????2?||?JESSIE?????|????????2?|  +------------+----------+2?rows?in?set?(0.00?sec)    (root@localhost)?[sakila]&gt;?explain?select?first_name?from?customer?where?first_name='JESSIE'G  ***************************?1.?row?***************************???????????  id:?1??  select_type:?SIMPLE????????  table:?customer?????????  type:?refpossible_keys:?idx_fisrt_last_name??????????  key:?idx_fisrt_last_name??????  key_len:?137??????????  ref:?const?????????  rows:?2????????  Extra:?Using?where;?Using?index1?row?in?set?(0.00?sec)    (root@localhost)?[sakila]&gt;?alter?table?customer?drop?index?idx_fisrt_last_name;  Query?OK,?599?rows?affected?(0.03?sec)  Records:?599??Duplicates:?0??Warnings:?0--下面演示出現在join是ref的示例  (root@localhost)?[sakila]&gt;?explain?select?b.*,a.*?from?payment?a?inner?join????  -&gt;?customer?b?on?a.customer_id=b.customer_idG  ***************************?1.?row?***************************???????????  id:?1??  select_type:?  SIMPLE????????  table:?b?????????  type:?ALLpossible_keys:?PRIMARY  ??????????key:?NULL  ??????key_len:?NULL??????????  ??????ref:?NULL?????????  ??????rows:?599????????  ??????Extra:?NULL  ??????***************************?2.?row?***************************???????????  ??????id:?1??  ??????select_type:?SIMPLE????????  ??????table:?a?????????  ??????type:?refpossible_keys:?idx_fk_customer_id??????????  ??????key:?idx_fk_customer_id??????  ??????key_len:?2??????????  ??????ref:?sakila.b.customer_id?????????  ??????rows:?13????????  ??????Extra:?NULL2?rows?in?set?(0.01?sec)    5、eq_ref  類似于ref,其差別在于使用的索引為唯一索引,對于每個索引鍵值,表中只有一條記錄與之匹配。  多見于主鍵掃描或者索引唯一掃描。  (root@localhost)?[sakila]&gt;?explain?select?*?from?film?a?join?film_text?b?  ????-&gt;?on?a.film_id=b.film_id;  +----+-------------+-------+--------+---------------+---------+---------+------------------+------+-------------+  |?id?|?select_type?|?table?|?type???|?possible_keys?|?key?????|?key_len?|?ref??????????????|?rows?|?Extra???????|  +----+-------------+-------+--------+---------------+---------+---------+------------------+------+-------------+  |??1?|?SIMPLE??????|?b?????|?ALL????|?PRIMARY???????|?NULL????|?NULL????|?NULL??????????|?1000?|?NULL???|  |??1?|?SIMPLE??????|?a?????|?eq_ref?|?PRIMARY???????|?PRIMARY?|?2???????|?sakila.b.film_id?|????1?|?Using?where?|  +----+-------------+-------+--------+---------------+---------+---------+------------------+------+-------------+  (root@localhost)?[sakila]&gt;?explain?select?title?from?film?where?film_id=5;  +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+  |?id?|?select_type?|?table?|?type??|?possible_keys?|?key?????|?key_len?|?ref???|?rows?|?Extra?|  +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+  |??1?|?SIMPLE??????|?film??|?const?|?PRIMARY???????|?PRIMARY?|?2???????|?const?|????1?|?NULL??|  +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+  6、const、system:  當MySQL對查詢某部分進行優化,這個匹配的行的其他列值可以轉換為一個常量來處理。  如將主鍵或者唯一索引置于where列表中,MySQL就能將該查詢轉換為一個常量  (root@localhost)?[sakila]&gt;?create?table?t1(id?int,ename?varchar(20)?unique);  Query?OK,?0?rows?affected?(0.05?sec)    (root@localhost)?[sakila]&gt;?insert?into?t1?values(1,'robin'),(2,'jack'),(3,'henry');  Query?OK,?3?rows?affected?(0.00?sec)  Records:?3??Duplicates:?0??Warnings:?0    (root@localhost)?[sakila]&gt;?explain?select?*?from?(select?*?from?t1?where?ename='robin')x;  +----+-------------+------------+--------+---------------+-------+---------+-------+------+-------+  |?id?|?select_type?|?table??????|?type???|?possible_keys?|?key???|?key_len?|?ref???|?rows?|?Extra?|  +----+-------------+------------+--------+---------------+-------+---------+-------+------+-------+|??  1?|?PRIMARY?????|?<derived2>?|?system?|?NULL??????????|?NULL??|?NULL????|?NULL??|????1?|?NULL??||??  2?|?DERIVED?????|?t1?????????|?const??|?ename?????????|?ename?|?2  3??????|?const?|????1?|?NULL??|  +----+-------------+------------+--------+---------------+-------+---------+-------+------+-------+  2?rows?in?set?(0.00?sec)    7、type=NULL  MySQL不用訪問表或者索引就可以直接得到結果  (root@localhost)?[sakila]&gt;?explain?select?sysdate();  +----+-------------+-------+------+---------------+------+---------+------+------+----------------+  |?id?|?select_type?|?table?|?type?|?possible_keys?|?key??|?key_len?|?ref??|?rows?|?Extra??????????|  +----+-------------+-------+------+---------------+------+---------+------+------+----------------+  |??1?|?SIMPLE??????|?NULL??|?NULL?|?NULL??????????|?NULL?|?NULL????|?NULL?|?NULL?|?No?tables?used?|  +----+-------------+-------+------+---------------+------+---------+------+------+----------------+  1?row?in?set?(0.00?sec)</derived2>

以上就是mysql explain type連接類型示例的內容,更多相關內容請關注php中文網(www.php.cn)!

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享