在關系型數據庫的底層存儲架構中,數據并不是隨意寫入磁盤,而是按照一定的結構分層管理的。理解這些存儲單位對于優化數據庫性能、理解 SQL 執行過程以及排查性能問題都具有重要意義。
我將從宏觀到微觀,依次介紹數據庫存儲中的四個核心概念:
- Segment(段)
- Extent(區)
- Page(頁)
- Row(行)
1. Segment(段)
Segment 是數據庫中用于表示一個完整數據對象(如表、索引等)在磁盤上所占據的所有空間的邏輯集合。
特點:
- 一個 segment 對應一個數據庫對象,比如某個表或某個索引。
- 由多個 extent 組成。
- 會隨著數據的增加自動擴展(例如 MySQL InnoDB 會自動分配更多 extent)。
- 通常一個 segment 屬于一個表空間(tablespace)。
舉例:
- 創建一個新表
user
,數據庫系統就會為它分配一個 segment。 - 插入數據后,該 segment 會動態增長,向系統請求更多的 extent。
2. Extent(區)
Extent 是一組連續的頁(Page),是數據庫分配磁盤空間的基本單位。
特點:
- 一般是固定大小(比如 InnoDB 默認是 1MB)。
- 多個 extent 組成一個 segment。
- 避免了頻繁地按頁分配所帶來的碎片問題。
舉例(不同數據庫的實現可能略有不同):
- MySQL InnoDB:一個 extent 通常由 64 個 16KB 的頁組成,即一個 extent 大小為 1MB。
- SQL Server:一個 extent 是 8 個 8KB 頁,即 64KB。
3. Page(頁)
Page(頁) 是數據庫中 最小的I/O單位,數據的讀取和寫入都是以頁為單位進行的。
特點:
- 每頁固定大小(常見為 8KB、16KB)。
- 一個 extent 中包含若干頁。
- 頁中除了數據之外,還包含頭部(元數據)、行目錄等信息。
4. Row(行)
Row(行) 是我們最熟悉的數據單位,即表中的一條記錄,最終被存儲在頁(Page)中。
特點:
- 一頁中通常可以存儲多行數據。
- 行的格式有固定長度和可變長度兩種。
- 若某一行太大,不能完全放入一個頁中,系統會使用溢出頁或外部存儲機制(如 PostgreSQL 的 TOAST、MySQL 的 BLOB)。
優化建議:
- 行長度影響頁能裝多少行,從而影響索引性能和緩存命中率。
- 盡量避免一行中包含超大字段,建議單獨設計表進行拆分。
總結:四者關系圖
層級 | 說明 | 示例大小(InnoDB) |
---|---|---|
Segment | 表或索引的所有空間總和 | N/A |
Extent | 一組連續的頁 | 1MB(64個16KB頁) |
Page | 數據讀寫的最小單位 | 16KB |
Row | 表中的一條記錄 | 變長(數十~數千字節) |