聚簇與非聚簇索引、回表及索引下推原理
引言
在數據庫領域,聚簇索引和非聚簇索引是至關重要的概念,它們在數據組織與存儲方式上截然不同,深刻影響著查詢性能。
聚簇索引:數據與索引的緊密結合
聚簇索引的核心特點是數據與索引存儲在一處。其非葉子節點存放索引字段值,葉子節點則承載對應記錄的整行數據。在InnoDB存儲引擎里,聚簇索引依表的主鍵構建,表數據會依照主鍵順序存儲于磁盤,保證了行的物理存儲順序與主鍵邏輯順序一致,這使得聚簇索引在查找時速度優勢顯著。
圖片
例如,若有一張員工表,以員工ID為主鍵構建聚簇索引,那么在查詢時,一旦定位到索引節點,即可直接獲取該行員工的全部信息,無需額外操作。
非聚簇索引:索引與數據的分離存儲
與聚簇索引相反,非聚簇索引將索引和數據分開存放。它的葉子節點包含索引字段值以及指向數據頁數據行的邏輯指針。在InnoDB中,非聚簇索引通常基于非主鍵字段創建,也被稱作二級索引。
圖片
如在上述員工表中,若針對員工年齡創建非聚簇索引,其葉子節點會存儲年齡值及對應的員工ID指針。這意味著通過非聚簇索引查詢時,先找到索引值對應的主鍵ID,再憑借主鍵ID去查找所需數據,此過程即為回表操作。
回表操作:非聚簇索引查詢的額外步驟
在InnoDB中,由于非聚簇索引葉子節點僅存儲主鍵值,當執行查詢時,如依據員工年齡查找員工其他信息,首先要通過非聚簇索引獲取主鍵ID,接著利用該主鍵ID再次查詢數據表以獲取完整數據,這增加了查詢的I/O開銷。相比之下,使用聚簇索引(主鍵索引)查詢則無需回表,效率更高。為減少回表次數,可借助覆蓋索引和索引下推技術優化。
覆蓋索引:減少數據讀取的高效策略
覆蓋索引是指查詢語句所需數據能直接從索引獲取,無需訪問數據表。例如,表中有聯合索引idx_key1_key2 (key1,key2),當執行SELECT key2 FROM covering_index_sample WHERE key1 = 'keytest';時,可直接利用索引返回結果,避免回表。
但需注意,若不符合最左前綴匹配原則,如SELECT key1 FROM covering_index_sample WHERE key2 = 'keytest';,雖看似覆蓋索引,但會掃描索引樹,無法有效利用索引。并且,若查詢信息不在聯合索引內,如SELECT key2, key3 FROM covering_index_sample WHERE key1 = 'keytest';也無法使用覆蓋索引。
索引下推:優化查詢性能的有力手段
索引下推是MySQL 5.6引入的默認開啟優化技術(可關閉)。以people表的(zipcode,lastname,firstname)索引為例,對于查詢SELECT * FROM people WHERE zipcode='123' AND lastname LIKE '%yian%' AND address LIKE '%Main Street%';,若未啟用索引下推,MySQL先依zipcode='123' 從存儲引擎獲取數據返回服務端,再在服務端判斷其他條件;啟用后,會先篩選符合zipcode='123'且滿足lastname LIKE '%yian%'的索引,符合條件才定位數據,有效減少回表次數。
不僅限于LIKE條件,聯合索引中非前導列因類型不匹配等原因索引失效需掃表回表時,如select d from t2 where a = "ni" and b = 1; (b 字段索引失效),也可利用索引下推優化。
在執行計劃中,使用索引下推時extra字段會顯示"Using index condition" 。