1. 什么是回表?
回表(Back to Table) 指的是 在使用非聚簇索引(輔助索引)查詢時,MySQL 需要 先通過索引找到主鍵 ID,然后再回到主鍵索引(聚簇索引)查詢完整數據,這一過程稱為回表。
2. 回表的示例
假設有一張 users
表:
CREATE TABLE users (id INT PRIMARY KEY, -- 主鍵name VARCHAR(50), -- 用戶名age INT, -- 年齡address VARCHAR(255), -- 地址INDEX idx_name (name) -- 創建 name 的輔助索引
) ENGINE=InnoDB;
如果執行以下查詢:
SELECT address FROM users WHERE name = 'Alice';
查詢執行過程:
- 先查 idx_name 索引,找到
name='Alice'
對應的id
(假設 id = 3)。 - 再回表查詢,根據
id=3
在聚簇索引(主鍵索引)中找到address
字段。
為什么要回表? 因為
idx_name
只存了name
和id
,但address
不在索引中,必須再回到主鍵索引查找完整數據。
3. 什么情況下會發生回表?
- 查詢的字段不在索引覆蓋范圍內(即非覆蓋索引查詢)。
- 使用二級索引(非主鍵索引)查詢,而查詢的字段不在索引列中。
4. 如何避免回表?
(1)使用覆蓋索引
如果查詢的字段已經包含在索引中,就可以避免回表:
CREATE INDEX idx_name_age ON users(name, address);
然后執行:
SELECT address FROM users WHERE name = 'Alice';
此時,idx_name_age
索引已經包含 name
和 address
,所以可以直接在索引中獲取數據,不需要回表。
(2)使用主鍵查詢
如果使用 id
(主鍵)查詢,就不需要回表:
SELECT address FROM users WHERE id = 3;
因為 InnoDB 的主鍵索引(聚簇索引)本身就存儲了完整數據,所以查詢 id
不會回表。
5. 總結
查詢方式 | 是否回表 | 原因 |
---|---|---|
主鍵查詢 (SELECT * FROM users WHERE id = 3) | ? 不會 | 因為主鍵索引(聚簇索引)包含完整數據 |
非主鍵索引查詢 (SELECT address FROM users WHERE name = ‘Alice’) | ? 會回表 | 先查 name 索引,再回表查 address |
覆蓋索引查詢 (SELECT name FROM users WHERE name = ‘Alice’) | ? 不會 | name 索引已經包含查詢字段 |
🚀 結論: MySQL InnoDB 避免回表的方法:
- 盡量使用覆蓋索引(讓查詢的所有字段都包含在索引中)。
- 使用主鍵查詢,避免使用非主鍵索引查詢非索引字段。
- 分析 EXPLAIN 結果,關注
Extra
字段是否包含"Using index"
(表示使用了覆蓋索引)。
這樣可以減少回表,提高查詢性能!🚀
6. 拓展:二級索引的葉子節點和非葉子節點存儲內容**
6.1 二級索引 B+ 樹結構示意
假設有如下 users
表:
CREATE TABLE users (id INT PRIMARY KEY, -- 聚簇索引name VARCHAR(50),age INT,INDEX idx_age (age) -- 二級索引
);
其中,表中的數據如下:
id | name | age |
---|---|---|
1 | Alice | 25 |
2 | Bob | 30 |
3 | Charlie | 35 |
6.2 完整的二級索引 B+ 樹結構
(30)/ \(25) (35)/ \ / \(age=25,id=1) (age=30,id=2) (age=35,id=3)
6.3 📌 結構解析
- 非葉子節點(索引鍵):
- 只存儲 索引列 age,用于 快速查找數據所在的葉子節點。
- 例如,
30
代表左側存<30
的數據,右側存>=30
的數據。
- 葉子節點(存儲實際索引數據):
- 存儲 索引列 age 和 主鍵 id,但 不存儲完整數據。
- 例如,葉子節點
(age=30, id=2)
說明age=30
的數據,主鍵id=2
。 - 葉子節點 通過主鍵 id 回表查詢完整數據。
6.4 二級索引查詢流程
查詢 SELECT * FROM users WHERE age = 30;
- 從非葉子節點找到 30 對應的葉子節點。
- 葉子節點存儲 (age=30, id=2),返回 id=2。
- 回表:用
id=2
查詢users
表的主鍵索引,獲取完整數據。
6.5 🔥 關鍵點總結
- 非葉子節點 只存索引 key(
age
),不存儲數據。 - 葉子節點 存
age
和 主鍵 ID,用于返回 ID 進行回表查詢。 - 回表查詢 是因為 二級索引不存完整數據,需要用主鍵 ID 進一步查詢。
- 優化方式:
- 覆蓋索引(例如
INDEX idx_age_name (age, name)
),讓查詢字段直接存入索引,避免回表。 - 合理設計主鍵,避免主鍵過大影響二級索引的存儲效率。
- 覆蓋索引(例如
這樣,你對二級索引的 存儲結構和查詢流程 是否更加清晰了呢? 😊🚀