mysql 中的explain關鍵字

LXH發表於2019-02-26

mysql優化在實際的開發中是很重要,有很多可以評估自己寫的sql的質量與效率,mysql為我們提供了一個輔助武器explain,它向我們展示了mysql接收到一條sql語句的執行計劃,根絕explain返回的結果可以知道sql寫的怎樣,

demo資料庫

建表語句

CREATE TABLE test (
  id    INT(11) NOT NULL AUTO_INCREMENT,
  uname VARCHAR(255),
  age int,
  PRIMARY KEY (id)
);

alter table test add index uname_index(uname);

複製程式碼

表中資料如下

id uname age
1 lxh 24
3 zhangsan 23
10 sdsx 12
11 x33 35

explain的關鍵字有很多,此處只講解最關鍵的type,key,rows

type

型別,官方全程“join type”,意思是“連線型別”,注意這裡不是字面意思量表之間的連結,確切說是資料庫引擎查詢表的一種方式,在《高效能mysql》一書中作者更是覺得稱呼它為訪問型別更貼切一些;

type的型別達到了14種之多,這裡只記錄和理解最重要且經常遇見的六種型別,它們分別是all,index,range,ref,eq_ref,const。從左到右,它們的效率依次是增強的

all

全表掃描,如果只是查詢一個資料項的sql出現了all型別,代表sql處於一種最原聲的狀態,有很大的優化空間,就好比一萬個人中找一個人,只能挨個找一遍 以test表為例

mysql 中的explain關鍵字

index

另一種方式的全表掃描,只不過是按照索引的順序,

mysql 中的explain關鍵字

ref

查詢條件列使用了索引而且不為主鍵和unique,意思就是雖然使用了索引,但該索引列的值並不唯一,有重複 比如,test表的索引是 uname

mysql 中的explain關鍵字

eq_ref

ref_eq 與 ref相比牛的地方是,它知道這種型別的查詢結果集只有一個,使用了主鍵或者唯一性索引進行查詢時, 下面這兩張表一張學生表,一張成績表,成績表裡的學生id,t_id,就是使用了主鍵

-- 建表語句
create table ref_stu2 (
  id    INT(11) NOT NULL AUTO_INCREMENT,
  uname VARCHAR(255),
  age   VARCHAR(255),
  PRIMARY KEY (id)
);

create table ref_score2 (
  id     INT(11) NOT NULL AUTO_INCREMENT,
  stu_id int(11) not null,
  score  int(11),
  PRIMARY KEY (id)
 
);

explain select * from ref_stu2 stu, ref_score2 sc where stu.id = sc.stu_id;
複製程式碼

輸出結果

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE stu NULL ALL PRIMARY NULL NULL NULL 1 100 NULL
1 SIMPLE sc NULL eq_ref uk_score_stuid uk_score_stuid 4 lxhtest.stu.id 1 100 NULL

const

將一個主鍵放置到where後面作為條件查詢,mysql優化器就能把這次查詢優化轉化為一個常量

explain select * from ref_stu2 stu where stu.id = 1;
複製程式碼

執行結果如下

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE stu null const PRIMARY PRIMARY 4 const 1 100 null

key

查詢使用到的索引,type型別為index_merge(查詢使用了兩個以上的索引)時,這裡可能出現兩個以上的索引,其他的select_type這裡只會出現一個。

rows

這裡是執行計劃中估算的掃描行數,不是精確值,值越小,代表效率越高

索引覆蓋

覆蓋索引(covering index)指一個查詢語句的執行只用從索引中就能夠取得,不必從資料表中讀取

參考 MySQL SQL 優化之覆蓋索引

關於like關鍵字是否用到索引

mysql 中的explain關鍵字

mysql 中的explain關鍵字

mysql 中的explain關鍵字
mysql 中的explain關鍵字

總結:like關鍵字是否使用索引的前提是做字首原則,即‘x’和‘x%’是使用索引的,他們的執行計劃中type都是range,rows都是比表的行數少的,而其他兩個type都是index,這種情況叫,全索引掃描,具體介紹如下, 如果模糊查詢時,查詢是否包含某個字串,可以採用locate函式,select * from test where locate("x",uname);查詢test表中uname欄位,含有字串‘x’的資料。

mysql 全表掃描、全索引掃描、索引覆蓋(覆蓋索引)

full index scan:全索引掃描,查詢時,遍歷索引樹來獲取資料行。如果資料不是密集的會產生隨機IO 在執行計劃中是Type列,index

full table scan:通過讀物理表獲取資料,順序讀磁碟上的檔案。這種情況會順序讀磁碟上的檔案。 在執行計劃中是Type列,all

covering index:覆蓋索引,如果where條件的列和返回的資料在一個索引中,那麼不需要回查表,那麼就叫覆蓋索引。 在執行計劃中是extra那一列,using index

full index scan vs full table scan

全索引掃描一般情況下比全表掃描好,但一定不是絕對的

大多數資料是存在磁碟上的,讀取磁碟的次數是影響效率的關鍵。 由於索引掃描後要利用索引中的指標去逐一訪問記錄,假設每個記錄都使用索引訪問,則讀取磁碟的次數是查詢包含的記錄數T; 如果表掃描則讀取磁碟的次數是儲存記錄的塊數B; 如果T>B 的話索引就沒有優勢了,對於大多數資料庫來說,這個比例是10%(oracle,postgresql等),最終執行的時候,先對結果數量估算,如果小於(T<B)這個比例用索引,大於的話即直接表掃描所以結果也就不一定咯。

引用網上的一個例子 已知如下資訊: 假設一張表含有10萬行資料--------100000行 我們要讀取其中20%(2萬)行資料----20000行 表中每行資料大小80位元組----------80bytes 資料庫中的資料塊大小8K----------8000bytes 所以有以下結果: 每個資料塊包含100行資料---------100行(資料塊大小/每行資料的大小 8000/80 ) 這張表一共有1000個資料塊--------1000塊(資料總條數/每個塊包含的資料個數 100000/100)

背後的故事:

通過索引讀取20000行資料 = 約20000個table access by rowid = 需要處理20000個塊來執行這個查詢(通過索引去讀資料,在索引中找到一個鍵值,然後這個鍵值對應的rowid去讀表資料,rowid只對應一條記錄,所以讀一個塊也只是為了找到對應rowid的那條記錄,所以一次在一個塊中只讀一條記錄) 而如果是全表掃描呢,這個表一共是1000塊,也就1000次讀取,採用後者明顯效率高。

小計:最近在看mongo,發現原來mongo裡也有這個關鍵字,哈哈,看來是通用的啊

參考連結: mysql中explain的type的解釋 你的like語句為啥沒索引

安利一個我的部落格:Linnxh的部落格

相關文章