MySQL優化 如何避免回表查詢?什麼是索引覆蓋?

2021-10-05 10:43:30 字數 3018 閱讀 9932

我們知道mysql底層使用的b+樹來儲存索引的,而且資料都存在葉子節點上。對於innodb來說,它的主鍵索引和行記錄是儲存在一起的,因此叫做聚集索引。

ps:myisam的行記錄是單獨儲存的,不和索引在一起,因此myisam是沒有聚集索引的。

除了聚集索引,其他的索引都叫非聚集索引。(普通索引,唯一索引等)

另外需要注意的,在innodb中有且只有乙個聚集索引。它有三種情況:

為了方便理解,下邊以 innodb 的主鍵索引和普通索引為例,看下它們的儲存結構。

建立一張表,結構如下,並新增幾條記錄(張三,李四,王五,孫七):

create

table

`student`

(`id`

int(11)

notnull

,`name`

varchar

(255

)collate utf8mb4_bin default

null

,`age`

int(11)

default

null

,primary

key(

`id`),

key`idx_stu`

(`name`))

engine

=innodb

default

charset

=utf8mb4 collate

=utf8mb4_bin

insert

into student(id,name,age)

values(1

,'zs',12

);insert

into student(id,name,age)

values(5

,'ls',14

);insert

into student(id,name,age)

values(9

,'ww',12

);insert

into student(id,name,age)

values(11

,'sq',13

);

在 innodb 中,主鍵索引的葉子節點儲存的是主鍵和行記錄,而普通索引的葉子節點儲存的是主鍵(對於 myisam來說主鍵索引的葉子節點儲存的是主鍵和對應行記錄的指標,普通索引的葉子節點儲存的是當前索引列和對應行記錄的指標)。

(1)id為pk,聚集索引,葉子節點儲存行記錄;

(2)name為key,普通索引,葉子節點儲存pk值,即id;

從上面的索引儲存結構,我們可以看到,在主鍵索引樹上,通過主鍵就可以一次性查出我們所需要的資料,速度非常快。

因為主鍵和行記錄就儲存在一起,定位到了主鍵,也就定位到了所要找的記錄,當前行的所有欄位都在這(這也是我們為什麼說,在建立表的時候,最好是建立乙個主鍵,查詢時也盡量用主鍵來查詢)。

對於普通索引,如例子中的name,則需要根據name的索引樹(非聚集索引)找到葉子節點對應的主鍵,然後在通過主鍵索引樹查詢一遍,才可以得到要找的記錄,這就是回表查詢

對於回表查詢來說,無疑會降低查詢的效率。那麼有什麼辦法讓他不回表呢?

什麼是索引覆蓋,就是不管是sql-server官網,還是mysql官網,都表達了:只需要在一棵索引樹上就能獲取sql所需的所有列資料,無需回表,速度更快。

常見的方法是:將被查詢的字段,建立到聯合索引裡去。

還是以上邊的表為例,現在 zs 對應的索引樹上邊,只有它本身和主鍵的資料,並不能覆蓋到 age 字段。那麼,我們就可以建立聯合索引,如 key(name,age)。並且,查詢的時候,顯式的寫出聯合索引對應的字段(name和age)。

建立聯合索引如下,

key

`idx_stu`

(`name`

,`age`

)

查詢語句修改如下,

-- 覆蓋聯合索引中的字段

select id,name,age from student where name=

'zs'

and age=

12;

這樣,當查詢索引樹的時候,就不用回表,可以一次性查出所有的字段。對應的索引樹結構如下:

ps:圖中,聯合索引中的字段(name,age)都應該出現在索引樹上的,這裡為了畫圖方便,且因資料量太小,沒有畫出來。只表現出了:葉子節點儲存了所有的聯合索引字段。

四、哪些場景可以利用索引覆蓋來優化sql?

場景1:全表count查詢優化user(pk id, name, ***);

直接:select count(name) from user;

不能利用索引覆蓋。

新增索引:

alter table user add key(name);

就能夠利用索引覆蓋提效。

場景2:列查詢回表優化

select id,name,*** … where name=『shenjian』;

這個例子不再贅述,將單列索引(name)公升級為聯合索引(name, ***),即可避免回表。

場景3:分頁查詢

select id,name,*** …

order by

name limit 500,100;

將單列索引(name)公升級為聯合索引(name, ***),也可以避免回表。

innodb聚集索引普通索引回表索引覆蓋,希望這1分鐘大家有收穫。

提示,如果你不清楚explain結果extra欄位為using index的含義,請閱讀前序文章:《如何利用工具,迅猛定位低效sql?》

避免mysql回表 mysql如何避免回表查詢

select id,name where name shenjian select id,name,where name shenjian 多查詢了乙個屬性,為何檢索過程完全不同?什麼是回表查詢?什麼是索引覆蓋?如何實現索引覆蓋?哪些場景,可以利用索引覆蓋來優化sql?這些,這是今天要分享的內容。畫...

如何避免回表查詢?什麼是索引覆蓋?

一 什麼是回表查詢?innodb有兩大類索引 innodb聚集索引和普通索引有什麼差異?innodb聚集索引的葉子節點儲存行記錄,因此,innodb必須要有,且只有乙個聚集索引 1 如果表定義了pk,則pk就是聚集索引 2 如果表沒有定義pk,則第乙個not null unique列是聚集索引 3 ...

mysql回表查詢

通俗的講就是,如果索引的列在 select 所需獲得的列中 因為在 mysql 中索引是根據索引列的值進行排序的,所以索引節點中存在該列中的部分值 或者根據一次索引查詢就能獲得記錄就不需要回表,如果 select 所需獲得列中有大量的非索引列,索引就需要到表中找到相應的列的資訊,這就叫回表。根據這個...