回表與覆蓋索引,索引下推

2021-10-21 10:29:04 字數 4373 閱讀 3872

通俗的講就是,如果索引的列在 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資料表 ...