MySQL使用 B+ 樹作為索引結(jié)構(gòu)的示例詳解
1、簡述
在日常開發(fā)中,SQL 查詢速度往往決定了系統(tǒng)響應(yīng)的快慢,而索引的底層結(jié)構(gòu)直接影響數(shù)據(jù)庫性能。你或許聽過:
“MySQL 索引使用的是 B+ 樹,而不是 Hash、紅黑樹、B 樹。”
但你是否真正理解:為什么偏偏是 B+ 樹?
本文將揭開 B+ 樹在 MySQL 中大行其道的秘密,并結(jié)合 Java 示例和 SQL 實(shí)踐幫助你徹底理解。
2、什么是索引?為什么重要?
索引是數(shù)據(jù)庫中的“加速器”,作用類似于書籍的目錄,它能快速定位數(shù)據(jù)位置,避免全表掃描。
索引結(jié)構(gòu)常見的實(shí)現(xiàn)方式:
| 結(jié)構(gòu) | 特點(diǎn) |
|---|---|
| Hash 表 | 精確查找快,但不支持范圍查詢 |
| 二叉搜索樹 | 理論好,但高度不穩(wěn)定 |
| 紅黑樹 | 自平衡,但節(jié)點(diǎn)過多,不適合磁盤 |
| B 樹 | 多路搜索,適合磁盤查找 |
| ? B+ 樹 | 兼顧范圍查找與磁盤效率,MySQL 首選 |
3、B+ 樹 與其他結(jié)構(gòu)的區(qū)別
3.1 B+ 樹 vs B 樹
| 特性 | B 樹 | ? B+ 樹 |
|---|---|---|
| 數(shù)據(jù)存儲位置 | 所有節(jié)點(diǎn)都存數(shù)據(jù) | 僅葉子節(jié)點(diǎn)存數(shù)據(jù) |
| 葉子節(jié)點(diǎn)結(jié)構(gòu) | 無需指針連接 | 有鏈表連接 |
| 范圍查詢性能 | 較差(需中序遍歷) | 極優(yōu)(鏈?zhǔn)奖闅v) |
| 均勻度 | 多層級有冗余 | 非葉子節(jié)點(diǎn)僅存索引 |
B+ 樹更適合數(shù)據(jù)庫的兩個(gè)場景:
- 范圍查找(BETWEEN、ORDER BY)
- 大量磁盤 I/O 操作(葉子節(jié)點(diǎn)有序鏈表,順序讀取更快)
3.2 為什么不是 Hash 索引
雖然 Hash 查找時(shí)間復(fù)雜度是 O(1),但存在嚴(yán)重缺陷:
| 缺點(diǎn) | 舉例 |
|---|---|
| ? 不支持范圍查詢 | WHERE age BETWEEN 20 AND 30 |
| ? 無法排序 | ORDER BY 無法利用 |
| ? 不支持聯(lián)合索引前綴匹配 | WHERE a = 1 AND b = 2 只能匹配全部 |
| ? 沖突概率高,影響性能 | hash 沖突時(shí)退化為鏈表 |
4、B+ 樹為什么適合 MySQL
4.1 高扇出,I/O 次數(shù)少
B+ 樹是“多叉平衡搜索樹”,每個(gè)節(jié)點(diǎn)可包含幾百甚至上千個(gè) key,大大降低樹的高度。
例如,扇出為 1000,1 億條數(shù)據(jù)只需 3 層:
根 → 中間層 → 葉子層(數(shù)據(jù))
每次查詢最多只需 3 次磁盤隨機(jī) I/O!
4.2 全部數(shù)據(jù)在葉子節(jié)點(diǎn),遍歷效率高
葉子節(jié)點(diǎn)之間是鏈表結(jié)構(gòu),天然支持范圍查詢、排序:
SELECT * FROM orders WHERE amount BETWEEN 100 AND 500 ORDER BY amount;
這種查詢在 B+ 樹中,只需要定位起點(diǎn)節(jié)點(diǎn)后順序遍歷,非???。
4.3 非葉子節(jié)點(diǎn)僅存索引,占用空間少
B+ 樹的非葉子節(jié)點(diǎn)不存儲數(shù)據(jù),只存索引字段,因此:
- 節(jié)點(diǎn)更小,磁盤頁能裝更多 key
- 樹高度更低,查詢更快
5、InnoDB 索引與 B+ 樹的關(guān)系
InnoDB 支持兩類 B+ 樹索引:
5.1 主鍵索引(聚簇索引)
數(shù)據(jù)存儲與主鍵索引綁定
葉子節(jié)點(diǎn)直接存儲整行數(shù)據(jù)
查詢主鍵非???/p>
SELECT * FROM users WHERE id = 100;
5.2 二級索引(輔助索引)
非主鍵字段索引
葉子節(jié)點(diǎn)存儲的是主鍵值(回表)
SELECT * FROM users WHERE email = 'xx@example.com';
如果 email 是二級索引,則先查 B+ 樹找到主鍵,再去主鍵索引查整行數(shù)據(jù),稱為 回表。
6、實(shí)踐樣例:驗(yàn)證 B+ 樹索引特性
創(chuàng)建測試表
CREATE TABLE user ( id INT PRIMARY KEY, name VARCHAR(50), age INT, INDEX idx_age (age) ) ENGINE=InnoDB;
插入數(shù)據(jù)
for (int i = 1; i <= 1000000; i++) {
String sql = "INSERT INTO user (id, name, age) VALUES (?, ?, ?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, i);
ps.setString(2, "User" + i);
ps.setInt(3, (int)(Math.random() * 100));
ps.executeUpdate();
}
查詢測試
-- 使用索引(范圍查詢) EXPLAIN SELECT * FROM user WHERE age BETWEEN 20 AND 30; -- 使用全表掃描(函數(shù)干擾索引) EXPLAIN SELECT * FROM user WHERE age + 0 = 25;
輸出分析
type = range:范圍索引使用成功
key = idx_age:使用了 age 索引
rows 明顯少于總行數(shù)
總結(jié):B+ 樹是數(shù)據(jù)庫索引的首選原因
| 優(yōu)勢 | 原因 |
|---|---|
| ? I/O 成本低 | 多路搜索,樹高低 |
| ? 范圍查詢高效 | 葉子節(jié)點(diǎn)有序鏈表 |
| ? 支持排序與前綴匹配 | WHERE、ORDER BY |
| ? 非葉節(jié)點(diǎn)存索引更緊湊 | 降低層級 |
| ? 回表機(jī)制高效 | 主鍵索引快速定位 |
7、結(jié)語
MySQL 使用 B+ 樹,不是偶然,而是對磁盤性能、查詢效率、排序能力等綜合考量的結(jié)果。在 Java 開發(fā)中理解這些底層原理,可以:
編寫更高效的 SQL
更合理地設(shè)計(jì)索引
減少因查詢慢帶來的系統(tǒng)瓶頸
到此這篇關(guān)于MySQL使用 B+ 樹作為索引結(jié)構(gòu)的示例詳解的文章就介紹到這了,更多相關(guān)MySQL B+樹索引內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章
相關(guān)文章
PbootCMS的SQLite數(shù)據(jù)庫轉(zhuǎn)換為MySQL數(shù)據(jù)庫幾種方法步驟
隨著業(yè)務(wù)的發(fā)展,數(shù)據(jù)從一個(gè)系統(tǒng)遷移到另一個(gè)系統(tǒng)是一個(gè)常見的需求,這篇文章主要介紹了PbootCMS的SQLite數(shù)據(jù)庫轉(zhuǎn)換為MySQL數(shù)據(jù)庫幾種方法步驟,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-02-02
Mysql避免重復(fù)插入數(shù)據(jù)的4種方式
這篇文章主要介紹了Mysql避免重復(fù)插入數(shù)據(jù)的4種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
MySQL8.0?索引優(yōu)化invisible?index詳情
這篇文章主要介紹了MySQL8.0?索引優(yōu)化invisible?index詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
mysql提示Changed limits: max_open_files: 2048 max_connections:
這篇文章主要介紹了mysql提示Changed limits: max_open_files: 2048 max_connections: 1910 table_cache: 64的解決,需要的朋友可以參考下2014-05-05
MySQL中使用PROFILING來查看SQL執(zhí)行流程的實(shí)現(xiàn)步驟
在MySQL中,PROFILING功能提供了一種方式來分析SQL語句的執(zhí)行時(shí)間,包括查詢執(zhí)行的各個(gè)階段,如發(fā)送、解析、優(yōu)化、執(zhí)行等,這對于診斷性能問題非常有用,本文給大家介紹了MySQL中使用PROFILING來查看SQL執(zhí)行流程的實(shí)現(xiàn)步驟,需要的朋友可以參考下2024-07-07
MySQL根據(jù) ID 將表 B 的字段更新到表 A的實(shí)戰(zhàn)教程
這篇文章主要介紹了MySQL根據(jù) ID 將表 B 的字段更新到表 A的實(shí)戰(zhàn)教程,本文將系統(tǒng)梳理幾種常見寫法,并分析它們的優(yōu)缺點(diǎn),需要的朋友可以參考下2026-04-04

