聚簇索引詳解
InnoDB 的聚簇索引特性
表數據本身就是聚簇索引:
- 數據行實際存儲在聚簇索引的葉子節點中
- "表就是索引,索引就是表"的結構
- 每個InnoDB表有且只有一個聚簇索引
? ? ? ? ?聚簇索引的葉子節點存儲的是:真實數據
主鍵作為聚簇索引:
CREATE TABLE users (id INT PRIMARY KEY, -- 此主鍵自動成為聚簇索引name VARCHAR(100),email VARCHAR(100) );
無顯式主鍵時的處理:
- 如果表沒有定義主鍵,InnoDB會選擇一個唯一的非空索引代替
- 如果沒有這樣的索引,InnoDB會隱式創建一個6字節的ROWID作為聚簇索引
聚簇索引的優勢
- 高效的主鍵查詢:直接通過B+樹定位到數據行
- 范圍查詢高效:連續的主鍵值物理存儲也相鄰
- 覆蓋索引優勢:需要的數據都在索引中時可避免二次查找
聚簇索引的缺點
- 插入速度依賴插入順序:最好按主鍵順序插入
- 更新主鍵代價高:可能導致行移動
- 全表掃描可能較慢:當主鍵不連續時
非聚簇索引(二級索引)
非聚簇索引結構
索引結構與數據分離:
- 索引B+樹的葉子節點不包含完整行數據
- 只存儲主鍵值(或ROWID)
查找過程需要回表:
二級索引查找 -> 找到主鍵 -> 通過主鍵到聚簇索引中查找完整數據
非聚簇索引示例
CREATE INDEX idx_name ON users(name); -- 創建非聚簇索引
非聚簇索引的特點
- 支持多個:一個表可以有多個非聚簇索引
- 存儲內容:索引列值 + 主鍵值
- 覆蓋索引優化:如果查詢的列都在索引中,可避免回表
? ? ? ? ?非聚簇索引的葉子節點存儲的是:索引列值 + 主鍵值
MyISAM 的非聚簇索引
MyISAM 存儲引擎使用的是純非聚簇索引結構:
- 數據.MYD文件:存儲實際數據行
- 索引.MYI文件:存儲所有索引
- 索引葉子節點存儲的是數據行指針(物理地址)
對比總結
特性 | InnoDB聚簇索引 | InnoDB非聚簇索引 | MyISAM非聚簇索引 |
---|---|---|---|
數據存儲位置 | 索引葉子節點 | 單獨存儲,引用主鍵 | 單獨.MYD文件 |
索引數量 | 每表1個 | 多個 | 多個 |
葉子節點內容 | 完整數據行 | 主鍵值 | 數據文件指針 |
查找過程 | 直接獲取數據 | 需要回表 | 直接通過指針訪問數據 |
主鍵查詢性能 | 最優(O(1)~O(logN)) | 需要兩次查找 | 需一次索引查找 |
范圍查詢性能 | 優秀(順序I/O) | 一般 | 一般 |
MyISAM 的非聚簇索引:葉子節點存儲的數據文件指針(相對于InnoDB非聚簇索引,避免了回表)
實際應用建議
合理設計主鍵:短、有序(如自增INT),利用好聚簇索引特性
避免隨機主鍵:如UUID會導致大量頁分裂和碎片
覆蓋索引優化:使查詢只需訪問索引避免回表
思考:
- 多實例應用從分布式ID服務獲取ID后,由于網絡延遲、處理速度差異等原因,后獲取到的ID可能先提交事務,導致數據庫中ID不是嚴格遞增的,而是呈現"插入"形式(即小ID的記錄可能出現在大ID之后)
(其實業務能容忍小范圍的不一致)
方案1:業務邏輯的提交操作,盡量靠后,避免提前獲取id?