Mysql什么是回表查詢和覆蓋索引


一、前言

  本文主要解釋以下幾個問題:

  1.什么是回表查詢?

  2.什么是索引覆蓋?

  3.如何實現索引覆蓋?

  4.那些場景可以利用索引覆蓋優化sql?

  本文實驗基於8.0版本innodb

二、回表查詢

  1.建表

CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  `sex` varchar(5) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  2.分析下面兩個查詢

explain select id,name from user where name='lihua'

explain select id,name,sex from user where name='lihua'

通過explain可以看出當我們增加了sex字段做查詢時extra為NULL,意味着本次查詢進行了“回表”操作,我們知道innodb采用B+樹聚集索引,主鍵和數據綁定在一起,主鍵索引b+樹的葉子節點存儲了數據信息,而普通索引葉子節點存儲的是主鍵值。因此,我們可以得知當通過普通索引查詢時無法直接定位行記錄,通常情況下,需要掃描兩遍索引樹。

select * from user where name='lisi';

還是以現有表舉例,它是如何執行的?

  1)先掃描name索引樹,找到主鍵值id=5。

  2)再掃描主鍵索引,找到對應行。

  這就是“回表查詢”,先定位主鍵值,再通過主鍵值定位行記錄,性能上較之直接查詢索引樹定位行記錄更慢。

三、覆蓋索引

  1.什么是覆蓋索引?

  1)只需要在一棵索引樹上就可以獲取sql所需所有的列數據,不需要回表,較之回表速度要更快。

  2)explain輸出結果extra字段為Using index時,觸發了索引覆蓋。

  2.如何實現覆蓋索引?

  辦法:將被查詢的字段建立到聯合索引中

  接我們上面的例子,因為我們對name字段建立了普通索引,且基於name的索引葉子節點存有主鍵id值,因此滿足了在一顆索引樹上獲得sql所需的所有列數據這一條件,通過觀察extra也可發現是Using Index無需回表。

select id,name from user where name='lihua'

  觀察第二個例子,因為sex並沒有被建立到聯合索引中,且在name索引樹上也無法直接獲得,因此只能通過回表查詢,兩次掃描索引樹,效率更低。

explain select id,name,sex from user where name='lihua'

  針對第二個例子,我們將sex建立到聯合索引中去。

ALTER TABLE `test`.`user` 
DROP INDEX `name`,
ADD INDEX `idx_name_sex`(`name`, `sex`);

   再次執行查詢,可以看到extra已經變為Using index了,命中了索引覆蓋無需回表。

四、使用索引覆蓋的場景

   1.count查詢優化

  先對表做修改增加一個address字段,直接count(address)全表查詢,可以發現extra為NULL,沒有利用到索引覆蓋。

ALTER TABLE `test`.`user` ADD COLUMN `address` varchar(255) NULL AFTER `sex`;
explain select count(address) from user

  現對address加索引,再做查詢,可以觀察到extra變為Using index使用了索引覆蓋。

ALTER TABLE `test`.`user` 
DROP INDEX `idx_name_sex`,
ADD INDEX `idx_name_sex`(`name`, `sex`, `address`) USING BTREE;

  2.列查詢回表優化,上述例二建立聯合索引解決。

  3.分頁查詢,也可建立聯合索引解決,針對下例可以建立(name,sex)覆蓋索引。

select id,name,sex ... order by name limit 500,100;

五、結語

  本文主要記錄mysql學習過程,如有錯誤請指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM