mysql優化在實際的開發中是很重要,有不少能夠評估本身寫的sql的質量與效率,mysql爲咱們提供了一個輔助武器explain,它向咱們展現了mysql接收到一條sql語句的執行計劃,根絕explain返回的結果能夠知道sql寫的怎樣,mysql
建表語句sql
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,rowsbash
類型,官方全程「join type」,意思是「鏈接類型」,注意這裏不是字面意思量表之間的連接,確切說是數據庫引擎查找表的一種方式,在《高性能mysql》一書中做者更是以爲稱呼它爲訪問類型更貼切一些;mysql優化
type的類型達到了14種之多,這裏只記錄和理解最重要且常常碰見的六種類型,它們分別是all,index,range,ref,eq_ref,const。從左到右,它們的效率依次是加強的oracle
全表掃描,若是隻是查找一個數據項的sql出現了all類型,表明sql處於一種最原聲的狀態,有很大的優化空間,就比如一萬我的中找一我的,只能挨個找一遍 以test表爲例 函數
另外一種方式的全表掃描,只不過是按照索引的順序, post
查找條件列使用了索引並且不爲主鍵和unique,意思就是雖然使用了索引,但該索引列的值並不惟一,有重複 好比,test表的索引是 uname性能
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 |
將一個主鍵放置到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 |
查詢使用到的索引,type類型爲index_merge(查詢使用了兩個以上的索引)時,這裏可能出現兩個以上的索引,其餘的select_type這裏只會出現一個。
這裏是執行計劃中估算的掃描行數,不是精確值,值越小,表明效率越高
覆蓋索引(covering index)指一個查詢語句的執行只用從索引中就可以取得,沒必要從數據表中讀取
總結:like關鍵字是否使用索引的前提是作前綴原則,即‘x’和‘x%’是使用索引的,他們的執行計劃中type都是range,rows都是比表的行數少的,而其餘兩個type都是index,這種狀況叫,全索引掃描,具體介紹以下, 若是模糊查詢時,查詢是否包含某個字符串,能夠採用locate函數,select * from test where locate("x",uname);
查詢test表中uname字段,含有字符串‘x’的數據。
full index scan:全索引掃描,查詢時,遍歷索引樹來獲取數據行。若是數據不是密集的會產生隨機IO 在執行計劃中是Type列,index
full table scan:經過讀物理表獲取數據,順序讀磁盤上的文件。這種狀況會順序讀磁盤上的文件。 在執行計劃中是Type列,all
covering index:覆蓋索引,若是where條件的列和返回的數據在一個索引中,那麼不須要回查表,那麼就叫覆蓋索引。 在執行計劃中是extra那一列,using index
全索引掃描通常狀況下比全表掃描好,但必定不是絕對的
大多數數據是存在磁盤上的,讀取磁盤的次數是影響效率的關鍵。 因爲索引掃描後要利用索引中的指針去逐一訪問記錄,假設每一個記錄都使用索引訪問,則讀取磁盤的次數是查詢包含的記錄數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的博客