通俗的講就是,如果索引的列在 select 所需獲得的列中(因為在 mysql 中索引是根據索引列的值進行排序的,所以索引節點中存在該列中的部分值)或者根據一次索引查詢就能獲得記錄就不需要回表,如果 select 所需獲得列中有大量的非索引列,索引就需要到表中找到相應的列的資訊,這就叫回表。
innodb聚集索引的葉子節點儲存行記錄,因此, innodb必須要有,且只有乙個聚集索引:
(1)如果表定義了主鍵,則pk就是聚集索引;
(2)如果表沒有定義主鍵,則第乙個非空唯一索引(not null unique)列是聚集索引;
(3)否則,innodb會建立乙個隱藏的row-id作為聚集索引;
先建立一張表,sql 語句如下:
create table xttblog
( id int primary key,
k int not null,
name varchar(16
),index (k)
)engine = innodb;
然後,我們再執行下面的 sql 語句,插入幾條測試資料。
insert into xttblog
(id, k, name)
values(1
,2,'xttblog'),
(2,1
,'業餘草'),
(3,3,);
假設,現在我們要查詢出 id 為 2 的資料。那麼執行 select * from xttblog where id = 2; 這條 sql 語句就不需要回表。原因是根據主鍵的查詢方式,則只需要搜尋 id 這棵 b+ 樹。主鍵是唯一的,根據這個唯一的索引,mysql 就能確定搜尋的記錄。
但當我們使用 k 這個索引來查詢 k = 2 的記錄時就要用到回表。select * from xttblog where k = 2; 原因是通過 k 這個普通索引查詢方式,則需要先搜尋 k 索引樹,然後得到主鍵 id 的值為 1,再到 id 索引樹搜尋一次。這個過程雖然用了索引,但實際上底層進行了兩次索引查詢,這個過程就稱為回表。
也就是說,基於非主鍵索引的查詢需要多掃瞄一棵索引樹。因此,我們在應用中應該盡量使用主鍵查詢。
我這裡表裡的資料量比較少,如果資料量大的話,你能很明顯的看出兩次查詢所用的時間,很明顯使用主鍵查詢效率更高。
(1)先通過普通索引定位到主鍵值id=5;
(2)在通過聚集索引定位到行記錄;
這就是所謂的回表查詢,先定位主鍵值,再定位行記錄,它的效能較掃一遍索引樹更低。
使用聚集索引(主鍵或第乙個唯一索引)就不會回表,普通索引就會回表。
只需要在一棵索引樹上就能獲取sql所需的所有列資料,無需回表,速度更快。
explain的輸出結果extra欄位為using index時,能夠觸發索引覆蓋。
例子
create table user (
id int primary key,
name varchar(20
),*** varchar(5
),index
(name)
)engine=innodb;
第乙個sql:
能夠命中name索引,索引葉子節點儲存了主鍵id,通過name的索引樹即可獲取id和name,無需回表,符合索引覆蓋,效率較高。
extra:using index。
第二個sql:
能夠命中name索引,索引葉子節點儲存了主鍵id,沒有儲存***,***字段必須回表查詢才能獲取到,不符合索引覆蓋,需要再次通過id值掃瞄聚集索引獲取***字段,效率會降低。
extra:using index condition。
如果把(name)單列索引公升級為聯合索引(name, ***)就不同了。
可以看到:
select id,name … where name=『shenjian』;
select id,name,*** … where name=『shenjian』;
單列索公升級為聯合索引(name, ***)後,索引葉子節點儲存了主鍵id,name,***,都能夠命中索引覆蓋,無需回表。
畫外音,extra:using index。
場景1:全表count查詢優化
原表為:
user(pk id, name, ***);
直接:select count(name) from user;
不能利用索引覆蓋。
新增索引:
alter table user add key(name);
就能夠利用索引覆蓋提效。
場景2:列查詢回表優化
這個例子不再贅述,將單列索引(name)公升級為聯合索引(name, ***),即可避免回表。
場景3:分頁查詢
將單列索引(name)公升級為聯合索引(name, ***),也可以避免回表。
如果需要索引很長的字串,此時需要考慮字首索引
如何選擇字首
使用多列索引
選擇合適的索引列順序
覆蓋索引
使用索引掃瞄來做排序
怎樣保證使用索引順序掃瞄:
壓縮索引
減少重複、冗餘以及未使用的索引
索引和鎖
減少索引和資料碎片假設有這麼個需求,查詢表中「名字第乙個字是張,性別男,年齡為10歲的所有記錄」。那麼,查詢語句是這麼寫的:
mysq> select * from tuser where name like '張 %' and age=
10 and ismale=
1;
根據前面說的「最左字首原則」,該語句在搜尋索引樹的時候,只能匹配到名字第乙個字是『張』的記錄(即記錄id3),接下來是怎麼處理的呢?當然就是從id3開始,逐個回表,到主鍵索引上找出相應的記錄,再比對age和ismale這兩個欄位的值是否符合。
但是!mysql 5.6引入了索引下推優化,可以在索引遍歷過程中,對索引中包含的字段先做判斷,過濾掉不符合條件的記錄,減少回表字數。
下面圖1、圖2分別展示這兩種情況。
圖 1 中,在 (name,age) 索引裡面我特意去掉了 age 的值,這個過程 innodb 並不會去看 age 的值,只是按順序把「name 第乙個字是』張』」的記錄一條條取出來回表。因此,需要回表 4 次。
圖 2 跟圖 1 的區別是,innodb 在 (name,age) 索引內部就判斷了 age 是否等於 10,對於不等於 10 的記錄,直接判斷並跳過。在我們的這個例子中,只需要對 id4、id5 這兩條記錄回表取資料判斷,就只需要回表 2 次。
如果沒有索引下推優化(或稱icp優化),當進行索引查詢時,首先根據索引來查詢記錄,然後再根據where條件來過濾記錄;在支援icp優化後,mysql會在取出索引的同時,判斷是否可以進行where條件過濾再進行索引查詢,也就是說提前執行where的部分過濾操作,在某些場景下,可以大大減少回表次數,從而提公升整體效能。
資料庫 回表 索引覆蓋 最左匹配 索引下推
1.回表 回表就是資料庫根據索引找到了我們需要的行,但是還需要根據其他條件來進一步過濾資料。解決方法 建立復合索引,但是也不能把所有的字段建立索引,儲存代價會很大。2.索引覆蓋 索引覆蓋就是在我們需要查詢的列上建立索引,覆蓋我們需要的字段。一般都是復合索引。3.最左匹配 最左匹配是針對復合索引的,比...
索引覆蓋 最左字首 索引下推
什麼是索引覆蓋?怎麼用到索引覆蓋 索引覆蓋的情況,using index using index using where select from t where k betwee 3 and 5 這條語句的執行流程是什麼樣的?邊界查詢 回表的概念是什麼?索引覆蓋的概念是什麼,索引覆蓋的優點是什麼?最...
mysql索引下推 MySQL中的索引下推
前段時間看了一下資料庫相關知識,出現了索引下推這個名詞,有必要記錄下來作為知識儲備。索引下推用一句話總結是 索引下推是資料庫檢索資料過程中為減少回表次數而做的優化。首先介紹下什麼是資料庫回表,回表是一種資料庫檢索過程。通常發生在使用二級索引檢索非主索引資料的過程中。舉個例子 usertest資料表 ...