在下面表T中,執行下面語句,須要執行幾回樹的搜索操做?會掃描多少行?mysql
select * from T where k between 3 and 5
mysql> create table T ( ID int primary key, k int NOT NULL DEFAULT 0, s varchar(16) NOT NULL DEFAULT '', index k(k)) engine=InnoDB; insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');
一、在 k 索引樹上找到 k=3 的記錄,取得 ID = 300...
二、再到 ID 索引樹查到 ID=300 對應的 R3;
三、在 k 索引樹取下一個值 k=5,取得 ID=500;
四、再回到 ID 索引樹查到 ID=500 對應的 R4;
五、在 k 索引樹取下一個值 k=6,不知足條件,循環結束。sql
這個過程當中回到主鍵索引樹搜索的過程,咱們稱爲回表,能夠看到這個查詢過程讀了K索引樹的3條記錄
(步驟一、3和5),回表了兩次(步驟一、3和5)性能優化
在上面的例子中,因爲查詢結果鎖須要的數據只在主鍵索引上有,因此不得不回表,
那麼。有沒有可能通過索引優化,避免回表過程?架構
select ID from T where k between 3 and 5
索引k已經"覆蓋了"咱們的查詢需求。咱們稱爲覆蓋索引性能
因爲覆蓋索引能夠減小樹的搜索次數,顯著提高查詢性能,因此使用覆蓋索引是一個經常使用的性能優化手段優化
假設這個市民表的定義是這樣的:spa
CREATE TABLE `tuser` ( `id` int(11) NOT NULL, `id_card` varchar(32) DEFAULT NULL, `name` varchar(32) DEFAULT NULL, `age` int(11) DEFAULT NULL, `ismale` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`), KEY `id_card` (`id_card`), KEY `name_age` (`name`,`age`) ) ENGINE=InnoDB
若是如今有一個高頻請求,要根據市民的身份證號查詢他的姓名,這個聯合索引就有意義了,
它能夠在這個高頻請求上用覆蓋索引、再也不須要回表查整行記錄,減小語句的執行時間3d
固然、索引字段的維護老是有代價的,創建冗餘索引來支持覆蓋索引時就須要權衡考慮了,這正是業務DBA,或者稱爲業務數據架構師的工做blog
單獨爲一個不頻繁的請求建立一個索引又感受有點浪費,應該怎麼作呢?索引
B+樹這種索引結構,能夠利用索引的"最左前綴",來定位記錄
快速定位到ID4,而後向後遍歷獲得全部須要的結果
where name like '張%'
查找到第一個符合條件的記錄是ID3,而後向後遍歷,知道不知足條件爲止。
你要查的是全部名字第一個字是「張」的人
不僅是索引的所有定義,只要知足最左前綴,就能夠可利用索引來加速檢索、這個最左前綴能夠是聯合索引的最左N個字段,也能夠是字符串索引的最左M個字符
索引的複用能力,
由於能夠支持最左前綴,因此已經有了(a,b)這兩個聯合所用後,通常就不須要單獨在b上面創建索引了
若是經過調整順序,能夠減小維護一個索引。那麼這個順序每每就是須要優先考慮採用的
同時維護(a,b)(b)這兩個索引、這時候咱們要考慮的原則就是空間了。
好比上面這個市民表的狀況、name字段是比age字段大的,那我就建議你建立一個(name,age)的聯合索引和一個(age)的字段索引
咱們仍是以市民表的聯合索引(name, age)爲例。檢索出表中:"名字第一個字是長,而年齡是10歲的全部男孩"
一、SQL語句是這麼寫的
mysql> select * from tuser where name like '張 %' and age=10 and ismale=1;
一、 找到第一個知足條件的記錄ID3(這還不錯,總比權標掃描要好)
二、判斷其餘是否知足條件
5.6以前只能從ID3開始一個一個回表,到主鍵索引上找出數據航,再對比字段值不去判斷age
每個虛線箭頭表示回表一次
一、InnoDB 並不會去看 age的值,
二、只是按順序把name的第一個子是'張'的記錄一條取出來回表,所以須要回表4次
5.6以後引入的索引下推優化,能夠在索引遍歷過程當中對索引中包含的字段先判斷,直接過濾掉不知足條件的記錄,減小回表次數
內部就判斷了age是否等於10
每個虛線箭頭表示回表一次
一、InnoDB 內部就哦按段了age是否等於10,
二、對不等於10的記錄,直接判斷跳過,在咱們這個例子中只須要對ID四、ID4回表2次
若是查詢條件使用的是普通索引(或是聯合索引的最左原則字段),查詢結果是聯合索引的字段或是主鍵,不用回表操做,直接返回結果,減小IO磁盤讀寫讀取正行數據
聯合索引的最左 N 個字段,也能夠是字符串索引的最左 M 個字符
根據建立聯合索引的順序,以最左原則進行where檢索,好比(age,name)以age=1 或 age= 1 and name=‘張三’可使用索引,單以name=‘張三’ 不會使用索引,考慮到存儲空間的問題,還請根據業務需求,將查找頻繁的數據進行靠左建立索引。
like 'hello%’and age >10 檢索,MySQL5.6版本以前,會對匹配的數據進行回表查詢。5.6版本後,會先過濾掉age<10的數據,再進行回表查詢,減小回表率,提高檢索速度