引入
本篇博客偏理論, 將會介紹以下知識:
- 索引介紹
- 索引原理
- 索引的資料結構(二叉樹--->平衡二叉樹--->B樹--->B+樹)
- 聚集索引與輔助索引
- MySQL索引管理
- 創建和洗掉索引的語法
- 創建索引后的測驗 (查詢速度的變化)
- 如何正確使用索引
- 回表
- 覆寫索引
- 聯合索引
- 最左前綴匹配
- 索引下推
- MySQL查詢優化 : explain
- 慢查詢優化的基本步驟
- 慢日志管理
一.索引介紹
1.什么是索引
- 索引是對資料庫表中一列或多列的值進行排序的一種資料結構, 使用索引可以快速訪問資料庫表中的特定資訊
- 為資料庫建立索引, 就好比為書建立目錄
2.為什么要有索引
- 優化資料查詢效率
資料庫的資料一般存盤在磁盤中, 相比較記憶體, 磁盤的訪問速度較慢索引就是可以幫助資料庫快速從磁盤中找到資料的一種資料結構
- 注意 : 創建索引后會降低增、刪、改的效率
雖然會降低, 但是一般的應用系統,讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現性能問題,遇到最多的,也是最容易出問題的,還是一些復雜的查詢操作,所以查詢陳述句的優化顯然是重中之重
3.為表創建的索引是不是越多越好?
- 多數情況下, 我們知道索引能夠提高查詢效率, 但過多也會影回應用程式效率, 怎么加才是關鍵
- 一個應用程式的設計, 資料上過多或過少的索引都會引發應用程式的效率問題, 所以我們需要找到一個平衡點
- 當表有大量資料的情況下, 創建索引的速度會很慢, 并且對于寫的性能也會大幅度降低
4.索引應該什么時候加才最合適
- 任何一個軟體都有其吸參考戶的亮點, 亮點背后對應的是熱資料, 無疑開發人員對熱資料的所對應的資料庫欄位有哪些, 應該在開發軟體的程序中就提前為相應的欄位加上索引, 而不是等軟體上線后讓DBA發現慢查詢sql后再做處理
原因 :
1.一個軟體慢會影響用戶體驗, 但是慢的原因有很多, 你不能立即確定就是 SQL 的問題, 當你定位到 SQL 問題的時候就已經過去很久了, 問題沒有得到及時的解決
2.大多數DBA都是管理型DBA而非開發型, 所以即便是DBA從日志中看到了慢查詢sql, 也會因為其不懂業務而很難分析出慢的原因
二.索引原理
1.索引的原理
- 通過不斷的縮小想要查詢的資料范圍篩選出最終的結果
就比如買火車票(無索引) : 如果沒有12360火車票訂購軟體, 擺在我們面前的就是成千上萬輛火車, 選擇那一輛的條件有火車型別、出發和終點、時間等等, 我們需要一輛一輛火車去比對自己的篩選條件, 運氣好第一輛就是要找的火車, 運氣不好第一千輛才是要找的火車
加入索引 : 現在我們只需要在12360軟體上選擇高鐵, 就能篩選掉不是高鐵的火車, 縮小了查詢范圍; 再輸入出發點和終點, 又縮小了查詢范圍; 再輸入時間, 范圍又減少, 最終找到自己需要的車次, 由不固定查詢次數變成很小的固定查詢次數
2.磁盤I/O與預讀
- I\O延遲
IO延遲 = 平均尋道時間 + 平均延遲時間(一般為9ms)--->例子:假設當前硬碟轉軸(盤片)轉速是7200/min,也就是120/s,那么轉一圈需要花費1/120≈8ms,半圈也就是4ms(假設找到資料要半圈)
9ms左右對于我們來講很短, 但對于一臺500-MIPS的機器來說每秒可以執行5億條指令, 換句話說執行一次IO的時間可以執行40萬條指令,資料庫動輒十萬百萬乃至千萬級資料,每次9毫秒的時間, 這簡直是場災難
- 預讀
考慮到磁盤IO是非常高昂的操作,計算機作業系統做了一些優化,當一次IO時,不光把當前磁盤地址的資料,而是把相鄰的資料也都讀取到記憶體緩沖區內,因為區域預讀性原理告訴我們,當計算機訪問一個地址的資料的時候,與其相鄰的資料也會很快被訪問到,每一次IO讀取的資料我們稱之為一頁(page),具體一頁有多大資料跟作業系統有關,一般為4k或8k,也就是我們讀取一頁內的資料時候,實際上才發生了一次IO,這個理論對于索引的資料結構設計非常有幫助
三.索引的資料結構
索引的資料結構是 B+樹, 而 B+樹 是經過 二叉排序樹 到 二叉平衡樹 再到 B樹 最后到 B+樹 演變過來的, 下面簡單介紹一下:
1.二叉排序樹(二叉查找樹)
- 頂端的節點我們稱為根節點,沒有子節點的節點我們稱之為葉節點(就是最下面一排)
對于一列數字 : 5、6、7、8、9、10

- 如果我們需要找到 key=9 的節點, 先將 9 與根節點比較, 大于根節點, 于是往右邊找; 繼續與右邊的 10 比較, 小于, 于是往左邊找, 正好找到九
利用二叉排序樹我們只需要3次即可找到匹配的資料; 如果在數字列中一條條的查找的話,我們需要5次才能找到
2.平衡二叉樹(AVL樹)
- 平衡二叉樹可以說是二叉排序樹的改進版, 是特殊的二叉排序樹
上面我們講解了利用二叉排序樹可以快速的找到資料; 但是,如果上面的二叉排序樹是這樣的構造:

平均查找長度是3, 如果我們調整一下關鍵字的序列

調整之后平均查找長度是 2.2, 從上面我們可以看出平均查找長度與數的高度有關, 平均查找長度越小, 查找速度就越快, 所以我們應該盡可能的讓這棵樹矮
- 怎么判斷一顆二叉樹是否是平衡二叉樹?
這里引入了平衡因子的概念, 左子樹的高度減右子數的高度就是平衡因子, 平衡因子的絕對值小于或等于一就是平衡二叉樹, 大于一就是非平衡二叉樹, 如下圖平衡因子為 4 就是非平衡二叉樹

我們調整一下關鍵字序列, 各子數平衡因子絕對值都小于或等于 1, 那么這就是一顆平衡二叉樹

3.B 樹 ( Balanced Tree)多路平衡查找樹
- 我們知道平衡二叉樹每個節點只能存盤一個鍵值和資料
如果我們要存盤海量的資料呢?可以想象到二叉樹的節點將會非常多,高度也會及其高,我們查找資料時也會進行很多次磁盤IO,我們查找資料的效率將會極低
- 為了解決平衡二叉樹的這個弊端,我們應該尋找一種單個節點可以存盤多個鍵值和資料的平衡樹, 也就是 B樹

從上圖可以看出,B樹相對于平衡二叉樹,每個節點(B樹中節點稱之為頁)存盤了更多的鍵值(key)和資料(data),并且每個節點擁有更多的子節點,子節點的個數一般稱為階,上述圖中的B樹為3階B樹,高度也會很低, 基于這個特性,B樹查找資料讀取磁盤的次數將會很少,資料的查找效率也會比平衡二叉樹高很多
假設每個節點可以儲存兩個值(不代表只能存兩個), 我們找到75:
- 先與 頁1 比較,在 35 右邊找到 p3指標 定位到 頁4
- 與 頁4 中的索引對比, 在 65-87 之間, 找到指標 p2, 定位到 頁10
- 與 頁10 中的索引對比, 找到相對應的 75
4.B+ 樹
- B+ 樹是對 B樹的進一步優化

- 通過上圖我們來對比下 B+ 樹與 B樹的不同:
B+ 樹非葉子節點上是不存盤資料的,僅存盤鍵值,而 B 樹節點中不僅存盤鍵值,也會存盤資料
之所以這么做是因為在資料庫中頁的大小是固定的,InnoDB 中頁的默認大小是 16KB,如果不存盤資料,那么就會存盤更多的鍵值,相應的樹的階數(節點的子節點樹)就會更大,樹就會更矮更胖,如此一來我們查找資料進行磁盤的 IO 次數又會再次減少,資料查詢的效率也會更快
B+ 樹的階數是等于鍵值的數量的,如果我們的 B+ 樹一個節點可以存盤 1000 個鍵值,那么 3 層 B+ 樹可以存盤 1000×1000×1000=10 億個資料,
一般根節點是常駐記憶體的,所以一般我們查找 10 億資料,只需要 2 次磁盤 IO
3層的b+樹可以表示上百萬的資料,如果上百萬的資料查找只需要兩次IO,性能提高將是巨大的,如果沒有索引,每個資料項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高
- B+ 樹的兩種性質
- 索引欄位要盡量的小 : 磁盤塊的大小也就是一個資料頁的大小,是固定的. 如果資料項占的空間越小,資料項的數量越多,樹的高度就越低, 查詢過的IO次數就越少. 這就是為什么每個資料項,即索引欄位要盡量的小,比如int占4位元組,要比bigint8位元組少一半,這也是為什么b+樹要求把真實的資料放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的資料項會大幅度下降, 下降則會導致每層可存盤的資料就少, 因為磁盤塊是固定的, 從而要增加層次, 進而導致樹增高, 樹增高意味著找到底層資料的IO次數增多, 導致查詢速度大幅度下降
- 索引的最左匹配特性 : 當b+樹的資料項是復合的資料結構,比如(name,age,sex)的時候,b+數是按照從左到右的順序來建立搜索樹的. 比如當(張三,20,F)這樣的資料來檢索的時候,b+樹會優先比較name來確定下一步的所搜方向,如果name相同再依次比較age和sex,最后得到檢索的資料. 但當(20,F)這樣的沒有name的資料來的時候,b+樹就不知道下一步該查哪個節點,因為建立搜索樹的時候name就是第一個比較因子,必須要先根據name來搜索才能知道下一步去哪里查詢, 比如當(張三,F)這樣的資料來檢索時,b+樹可以用name來指定搜索方向,但下一個欄位age的缺失,所以只能把名字等于張三的資料都找到,然后再匹配性別是F的資料了, 這個是非常重要的性質,即索引的最左匹配特性
5.總結 B+ 樹優點
- 在二叉樹、平衡二叉樹、B樹的基礎上做了進一步優化, 只有葉子節點放真正的資料,這意味著在等量資料的前提下,B+樹的高度是最低的
- B+的葉子節點都是排好序的,這意味著在范圍查詢上,B+樹比B樹更快,快就快在一旦找到一個樹葉節點,就不需要在再從樹根查起了
四.聚集索引與輔助索引
資料庫中的 B+樹 索引可以分為聚集索引(clustered index)和輔助索引(secondary index), 聚集索引與輔助索引相同的是:不管是聚集索引還是輔助索引,其內部都是B+樹的形式,即高度是平衡的, 不同的是 :
聚集索引的葉子節點存放的是一整行完整的資訊, 而輔助索引的葉子節點存放的并非完整資訊(下面介紹)
1.聚集索引 (Clustered Index)
InnoDB 聚集索引的葉子節點存盤行記錄,因此 InnoDB 必須要有且只有一個聚集索引
-
如果表定義了 PK (Primary Key,主鍵),那么 PK 就是聚集索引
-
如果表沒有定義 PK,則第一個不為空且唯一(NOT NULL UNIQUE) 的列就是聚集索引
-
否則 InnoDB 會另外創建一個隱藏的 ROWID 作為聚集索引
由于這種機制是直接定位行記錄,因此使得基于 PK 的查詢速度非常快
2.輔助索引( Secondary Index )
表中除了聚集索引外其他索引都是輔助索引(Secondary Index,也稱為非聚集索引)
-
與聚集索引的區別是:輔助索引的葉子節點不包含行記錄的全部資料,葉子節點除了包含鍵值以外,每個葉子節點中的索引行中還包含一個書簽(bookmark),該書簽用來告訴InnoDB存盤引擎去哪里可以找到與索引相對應的行資料
-
輔助索引的存在并不影響資料在聚集索引中的組織,因此每張表上可以有多個輔助索引,但只能有一個聚集索引
-
當通過輔助索引來尋找資料時,InnoDB存盤引擎會遍歷輔助索引并通過葉子級別的指標獲得指向主鍵索引的主鍵,然后再通過主鍵索引來找到一個完整的行記錄
五.Mysql 索引管理
1.功能
- 索引的功能就是加速查找
- mysql中的primary key,unique,聯合唯一也都是索引,這些索引除了加速查找以外,還有約束的功能
2.mysql 中常用的索引(鍵)
- 普通索引: index 加速查找
- 唯一索引:
- 主鍵索引: primary key 加速查找+約束
- 唯一索引: unique key 加速查找+約束
- 聯合索引:
- 聯合主鍵索引: primary key
- 聯合唯一索引: unique(欄位1, 欄位2, ...)
- 聯合普通索引: unique(欄位1, 欄位2, ...)
上面的三種索引, 唯一索引除了可以增加查詢速度之外各自還具有約束條件, 而普通索引index key沒有任何的約束條件,只是用來幫助你加快速查詢資料
注意:聯合索引不是用來加速查詢用的,不在我們的而研究范圍之內
3.索引的兩大型別
- 我們可以在創建索引的時候, 為其指定索引型別(兩類)
hash型別的索引:查詢單條快,范圍查詢慢
btree型別的索引:b+樹,層數越多,資料量指數級增長(我們就用它,因為innodb默認支持它)
- 不同的存盤引擎支持的索引型別也不一樣
InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引
MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引
Memory 不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引
NDB 支持事務,支持行級別鎖定,支持 Hash 索引,不支持 B-tree、Full-text 等索引
Archive 不支持事務,支持表級別鎖定,不支持 B-tree、Hash、Full-text 等索引
六.創建和洗掉索引語法
1.創建的三種方法
- 語法
??方式一 : 創建表時建索引
create table [表名] (
[unique|fulltext|spatial] [index|key] [索引名] [欄位名(長度)] [asc|desc]
);
??方式二 : 在已存在的表上創建
create [unique|fulltext|spatial] index [索引名]
on [表名] [欄位名(長度)] [asc|desc];
??方式二 : alter 在已存在的表上創建索引
alter table [表名] add [unique|fulltext|spatial] index
[索引名] [欄位名(長度)] [asc|desc];
- 示例代碼
??方式一
create table t01(
id int,
name char(10),
age int,
sex enum("male","female"),
unique key unique_id(id),
index index_name(name) # index沒有key
);
??方式二
create index index_age on t01(age);
??方式三
alter table t01 add index index_sex(sex);
2.洗掉索引
drop index [索引名] on t01; # 語法
drop index index_age on t01; # 示例
七.索引測驗
1.先準備一張表, 并插入大量的資料
??創建表
create table t01(
id int,
name varchar(10),
sex enum("male","female"),
email varchar(18)
);
??創建存盤程序,進行自動插入記錄
delimiter %%%
create procedure p01()
begin
declare i int default 1;
while(i<3000000)do
insert t01 value(i,"shawn","male",concat("shawn",i,"@163.com"));
set i=i+1;
end while;
end %%%
delimiter ;
??查看存盤程序
show create procedure p01\G # \G 垂直顯示結果
??呼叫存盤程序
call p01(); # windows執行測驗大概一個半小時,3百萬條記錄,200多M
??洗掉存盤程序
drop procedure p01;

2.沒有建立索引的情況下測驗查詢速度
select * from t01 where id=3000000;
沒有索引,mysql不知道有沒有這條記錄, 所以從頭到尾的對記錄進行遍歷,有多少磁盤塊就要進行多少I\O,速度很慢

3.為表的某個欄位建立索引(表已經存在大量記錄,創建速度會很慢)
create index index_id on t01(id); # 為 id 欄位建立普通索引
觀察 data 檔案夾下的 t01 表資料檔案大小增加了



4.使用建立了索引的欄位設定為條件進行查詢
select * from t01 where id=3000000; # 可以觀察到速度明顯的提升

5.步驟分析
-
mysql先去索引表里根據 b+樹 的搜索原理很快搜索到 id 等于3000000的記錄,直接命中索引, IO大大降低,因而速度明顯提升
-
我們以沒有建立索引的欄位設定為條件來進行查詢, 可以發現速度依然很慢
select * from t01 email="[email protected]"; # 并且記錄越大查詢越慢
-
對 email 欄位建立索引試試
create index index_email on t01(email); # 欄位資料越大,建立的時間越長(所以建議不要使用資料很大的欄位建立索引,這里只是做實驗)
select * from t01 where email="[email protected]"; # 再去查詢,可以發現速度是數量級的提升

八.正確使用索引
并不是說創建了索引就一定能加速查詢, 有些情況就算命中了索引也未必能起到很好的提速效果, 下面來測驗一下各種情況 (如果不想看程序,可以直接看小結末尾的結論)
1.范圍查詢情況 : 或者說條件不明確, 條件中有 : >、>=、<、<=、!= 、between...and...、like
- 大小于 : >、<

- 不等于 : !=

- between...and...

- 模糊匹配 : like

2.區分度情況 : 區分度表示欄位不重復的比例, 區分度越大, 掃描的速度就越快,像主鍵唯一, 而性別欄位區分度就很低

出現上面的情況就是因為欄位的區分度太低, 在 B+樹 中對于這些欄位無法比較大小, 因為值都是相等的, 毫無疑問,只能增加樹的高度來保證這些資料的存盤, 樹的高度越高, 查詢速度就越慢
3.=和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式
4.索引列不要參與計算或者函式, 比如薪資乘與12 : 不要使用欄位相乘(salary*12=10000), 可以使用該欄位所對應的值相乘(salary=10000*12)

5.索引下推技術
??"and"與"or"的邏輯
[條件1] and [條件2] : 所有條件都成立才算成立,但凡要有一個條件不成立則最終結果不成立
[條件1] or [條件2] : 只要有一個條件成立則最終結果就成立
??"and"的作業原理
條件:
a = 10 and b = 'xxx' and c > 3 and d =4
索引:
制作聯合索引(d,a,b,c)
作業原理:
對于連續多個and:mysql會按照聯合索引,從左到右的順序找一個區分度高的索引欄位(這樣便可以快速鎖定很小的范圍),加速查詢,即按照d—>a->b->c的順序
??"or"的作業牌原理
條件:
a = 10 or b = 'xxx' or c > 3 or d =4
索引:
制作聯合索引(d,a,b,c)
作業原理:
對于連續多個or:mysql會按照條件的順序,從左到右依次判斷,即a->b->c->d
6.最左前綴匹配原則
7.總結 (怎么建立索引能提高查詢效率)
- 對區分度高并且占用空間小的欄位建立索引
- 針對范圍查詢命中了索引,如果范圍很大,查詢效率依然很低,如何解決
- 要么把范圍縮小
- 要么就分段取值,一段一段取最終把大范圍給取完
- 不要把查詢欄位放到函式或者參與運算
- 索引下推技術,mysql自動選擇查詢速度最優的那條陳述句 (默認是開啟)
- 索引覆寫 (下面介紹)
- 最左前綴匹配原則 (下面介紹)
8.其他注意事項
- 避免使用select *
- count(1)或count(列) 代替 count(*)
- 創建表時盡量時 char 代替 varchar
- 表的欄位順序固定長度的欄位優先
- 組合索引代替多個單列索引(經常使用多個條件查詢時)
- 盡量使用短索引
- 使用連接(JOIN)來代替子查詢(Sub-Queries)
- 連表時注意條件型別需一致
- 索引散列值(重復少)不適合建索引,例:性別不適合
九.回表、覆寫索引、聯合索引、最左前綴
匹配原則、索引下推
1.創建一張表, 并插入記錄
create table user(
-> id int not null auto_increment,
-> name char(16) not null,
-> age int not null,
-> primary key(id), # id 為主鍵并設定索引(聚集索引)
-> index index_name(name)); # name 欄位設定索引(輔助索引)
insert user(name,age) value
-> ("shawn",23),
-> ("song",22),
-> ("hai",20),
-> ("xing",18),
-> ("yanxi",45),
-> ("zichen",25);

2.回表
select * from user where id=2;
上面為主鍵查詢方式, 即通過聚集索引, 能找到 id 為 2 的完整記錄
select * from user where name="song";
上面為輔助索引查詢方式, 則需要先搜索 name 索引樹,得到 song 對應的 id 值為 2,再到 id 索引樹搜索一次, 這個程序稱為回表
- 結論 : 所以基于輔助索引的查詢需要多掃描一棵索引樹,因此,我們在應用中應該盡量使用聚集索引
3.覆寫索引
select id from user where name="hai";
上面陳述句查詢的條件是 name 欄位, name 欄位有索引樹, 并且上面保存有 name 和 id 的值, 可以直接提供查詢結果, 不需要進行回表操作, 也就是說, 在這個查詢里面, 索引 name 已經覆寫了我們所要查詢的 id 欄位需求, 這就稱為覆寫索引
select age from user where name="xing";
上面陳述句通過 name 索引樹找到 name 欄位對應的 "xing" 和 id 值, 但沒有 age 欄位資訊, 于是通過 id 欄位進行回表操作查找到滿足條件的資料
- 回表操作無疑是降低效率的, 我們可以再為 age 建立索引, 避免索引太多可能引起的效率問題, 也可以為其建立聯合索引
4.聯合索引、最左匹配原則
??聯合索引是指對表上的多個列合起來做一個索引. 聯合索引的創建方法與單個索引的創建方法一樣,不同之處在僅在于有多個索引列
??最左前綴匹配原則, 是非常重要的原則, mysql會從左到右進行匹配
- 先洗掉 name 欄位的索引, 再與 age 一起建立聯合索引
drop index index_name on user;
create index index_name_age on user(name,age); # 實際應用中應該把最常用的欄位放在最左邊
- 當查詢條件中出現以下欄位,可以命中聯合索引,因為符合最左前綴原則
select name,age from user where name="song"; # 條件欄位 name
select name,age from user where name="song" and age>18; # 條件欄位 name + age
- 查詢條件中只出現一個 age 欄位,不能命中聯合索引
select name,age from user where age=2; # 條件欄位 age (不會走聯合索引)
5.索引下推 (mysql自動開啟)
索引下推(index condition pushdown )簡稱ICP,在Mysql5.6的版本上推出,用于優化查詢
使用最左前綴匹配原則 + 聯合查詢可以加快查詢速度, 如果我們的條件存在范圍查詢, 那么 SQL 陳述句是怎么運行的呢?
select * from user where name like "s%" and age=22;

如上表的記錄, "s" 開頭的記錄有兩條
- Mysql 5.6 以前 沒有索引遞推這個優化
Innodb 會忽略 age 這個欄位, 直接通過 name 來進行查詢, 在(name,age)這個聯合索引上找到兩條結果, 然后拿到 id 為 1 和 2 進行"兩次回表查詢"
- Mysql 5.6 及以后 添加了索引下推這個優化
Innodb 不會忽略 age 這個欄位, 而是在索引內部就判斷了 age 是否等于 22, 不等于 22 的記錄直接跳過
因此在(name,age)這個聯合索引上只匹配到一個記錄, 此時拿著這一個 id 去回表到所有的資料只需要"回表一次"
十.MySQL查詢優化 : explain
官方檔案 : https://dev.mysql.com/doc/refman/8.0/en/explain-output.html
ps : 強調 rows 是核心指標,絕大部分 rows 小的陳述句執行一定很快,所以優化陳述句基本上都是在優化rows
1.explain 是什么
explain 簡稱查看執行計劃,使用 explain 關鍵字可以模擬優化器執行SQL查詢陳述句,從而知道MySQL 是如何處理 SQL 陳述句的
2.explain 如何使用
語法 : explain + [SQL陳述句]
3.explain 的作用
- 表的讀取順序
- 資料讀取操作的操作型別
- 哪些索引可以使用
- 哪些索引實際使用
- 表之間的參考
- 每張表有多少行被優化器查詢
4.執行計劃表包含的欄位資訊
explain select * from t01;

5.計劃表欄位說明
- id 欄位
| 欄位 | 說明 |
|---|---|
| id | MySQL Query Optimizer 選定的執行計劃中查詢的序列號,表示查詢中執行 select 子句或操作表的順序,id值越大優先級越高,越先被執行; 若id 相同,執行順序由上至下 |
- select_type 欄位
| select_type 查詢型別 | 說明 |
|---|---|
| SIMPLE | 簡單的 select 查詢,不使用 union 及子查詢 |
| PRIMARY | 最外層的 select 查詢 |
| UNION | UNION 中的第二個或隨后的 select 查詢,不 依賴于外部查詢的結果集 |
| DEPENDENT UNION | UNION 中的第二個或隨后的 select 查詢,依 賴于外部查詢的結果集 |
| SUBQUERY | 子查詢中的第一個 select 查詢,不依賴于外 部查詢的結果集 |
| DEPENDENT SUBQUERY | 子查詢中的第一個 select 查詢,依賴于外部 查詢的結果集 |
| DERIVED | 用于 from 子句里有子查詢的情況, MySQL 會 遞回執行這些子查詢, 把結果放在臨時表里 |
| UNCACHEABLE SUBQUERY | 結果集不能被快取的子查詢,必須重新為外 層查詢的每一行進行評估 |
| UNCACHEABLE UNION | UNION 中的第二個或隨后的 select 查詢,屬 于不可快取的子查詢 |
- table 欄位
| 欄位 | 說明 |
|---|---|
| table | 輸出行所參考的表 |
- type 欄位
非常重要的項, 顯示連接使用的型別, 按最優到最差的型別排序
| type : 連接型別 | 說明 |
|---|---|
| system | 表僅有一行(=系統表),這是 const 連接型別的一個特例 |
| const | const 用于用常數值比較 PRIMARY KEY 時,當 查詢的表僅有一行時,使用 System |
| eq_ref | const 用于用常數值比較 PRIMARY KEY 時,當 查詢的表僅有一行時,使用 System |
| ref | 連接不能基于關鍵字選擇單個行,可能查找 到多個符合條件的行, 叫做 ref 是因為索引要 跟某個參考值相比較,這個參考值或者是一 個常數,或者是來自一個表里的多表查詢的 結果值 |
| ref_or_null | 如同 ref, 但是 MySQL 必須在初次查找的結果 里找出 null 條目,然后進行二次查找, |
| index_merge | 說明索引合并優化被使用了 |
| unique_subquery | 在某些 IN 查詢中使用此種型別,而不是常規的 ref:value IN (SELECT primary_key FROM single_table WHERE some_expr) |
| index_subquery | 在 某 些 IN 查 詢 中 使 用 此 種 類 型 , 與 unique_subquery 類似,但是查詢的是非唯一 性索引: value IN (SELECT key_column FROM single_table WHERE some_expr) |
| range | 只檢索給定范圍的行,使用一個索引來選擇 行,key 列顯示使用了哪個索引,當使用=、 <>、>、>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 運算子,用常量比較關鍵字列時,可 以使用 range |
| index | 全表掃描,只是掃描表的時候按照索引次序 進行而不是行,主要優點就是避免了排序, 但是開銷仍然非常大 |
| all | 最壞的情況,從頭到尾全表掃描 |
- possible_keys 欄位
| 欄位 | 說明 |
|---|---|
| possible_keys | 指出 MySQL 能在該表中使用哪些索引有助于 查詢,如果為空,說明沒有可用的索引 |
- key 欄位
| 欄位 | 說明 |
|---|---|
| key | MySQL 實際從 possible_key 選擇使用的索引, 如果為 NULL,則沒有使用索引,很少的情況 下,MYSQL 會選擇優化不足的索引,這種情 況下,可以在 SELECT 陳述句中使用 USE INDEX (indexname)來強制使用一個索引或者用 IGNORE INDEX(indexname)來強制 MYSQL 忽略索引 |
- key_len 欄位
| 欄位 | 說明 |
|---|---|
| key_len | 使用的索引的長度,在不損失精確性的情況 下,長度越短越好, |
- ref 欄位
| 欄位 | 說明 |
|---|---|
| ref | 顯示索引的哪一列被使用了 |
- rows 欄位
| 欄位 | 說明 |
|---|---|
| rows | MYSQL 認為必須檢查的用來回傳請求資料的行數 |
- Extra 欄位
| extra 項 | 說明 |
|---|---|
| Using filesort | 表示 MySQL 會對結果使用一個外部索引排序,而不是從表里按索引次序讀到相關內容,可能在記憶體或者磁盤上進行排序,MySQL 中無法利用索引完成的排序操作稱為“檔案排序” |
| Using temporary | 表示 MySQL 在對查詢結果排序時使用臨時表,常見于排序 order by 和分組查詢 group by |
6.示例
explain select * from t01 where id=100000;
explain select * from t01 where id>10000 and id<20000;
explain select * from t01 where id>20000;

十一.慢查詢優化的基本步驟
- 先運行看看是否真的很慢,注意設定SQL_NO_CACHE
- where條件單表查,鎖定最小回傳記錄表,這句話的意思是把查詢陳述句的where都應用到表中回傳的記錄數最小的表開始查起,單表每個欄位分別查詢,看哪個欄位的區分度最高
- explain查看執行計劃,是否與1預期一致(從鎖定記錄較少的表開始查詢)
- order by limit 形式的sql陳述句讓排序的表優先查
- 了解業務方使用場景
- 加索引時參照建索引的幾大原則
- 觀察結果,不符合預期繼續從第一個步驟開始分析
十二.慢日志管理
慢日志管理 : https://www.cnblogs.com/songhaixing/p/14448814.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/263695.html
標籤:MySQL
