今天我們要更深入聊聊索引的架構,看看它們底層到底怎麼跑的。其實搞懂索引的結構,不只可以知道為什麼查詢會變快,還能幫你針對不同需求挑最適合的索引。
講到索引結構,就是在說資料在索引裡是怎麼被組織起來,好讓搜尋變快。想像一下有個文件櫃。如果文件全部亂塞一堆,要找東西超麻煩。但如果櫃子是照字母順序排好,找資料就簡單多了。索引就是這樣:它們把資料排好,讓你可以超快找到想要的資訊。
B-TREE 索引結構
B-TREE(balanced tree — 平衡樹)是 PostgreSQL 裡最常用的索引類型。基本上,它是一種樹狀結構,資料被分在不同節點裡,搜尋時會從樹根一路往下找到葉子節點。
大概長這樣:
樹根
/ | \
節點 1 節點 2 節點 3
/ \ | / \
葉子1 葉子2 葉子3 葉子4 葉子5
每個節點都會放關鍵值,幫助你導引搜尋。例如,如果樹根節點有 [10, 20, 30] 這些值:
- 所有小於
10的資料都在 葉子1。 - 所有介於
10和20之間的資料在 葉子2,依此類推。
B-TREE 索引的優點:
- 搜尋超快:搜尋複雜度是
O(log n),比線性搜尋快很多。 - 很適合做範圍查詢(像是找所有介於
10和50之間的值)。
舉個例子: 假設我們有個 students 表格,裡面有個 age 欄位。當我們在這個欄位上建立 B-TREE 索引:
CREATE INDEX age_idx ON students (age);
PostgreSQL 會幫年齡值建一棵平衡樹,這樣你要找某個年齡或年齡範圍的學生就超快。
B-TREE 裡的搜尋演算法
當你下查詢時,PostgreSQL 會這樣用索引來找資料:
- 決定搜尋的 key(例如年齡
25)。 - 從樹根節點開始。
- 把 key 跟節點裡的值比對,然後走到對應的子節點。
- 重複第 3 步,直到走到葉子節點。
- 從葉子節點拿出對應 key 的資料。
查詢範例:
SELECT * FROM students WHERE age = 25;
索引會大幅減少要掃的資料量,讓搜尋變超快。
搜尋演算法與效能
索引能加速搜尋,是因為它們減少你要掃的資料筆數。沒索引時,PostgreSQL 會掃整張表(這叫 順序掃描,也就是 Seq Scan)。有索引時,會用 索引掃描(Index Scan),快很多。
順序掃描 vs 索引掃描
順序掃描(
Seq Scan):- PostgreSQL 會讀每一筆資料,檢查查詢條件,然後回傳符合的資料。
- 如果沒索引,或查詢幾乎涵蓋整張表,就會用這個。
索引掃描(
Index Scan):- PostgreSQL 會用索引先找到對應的資料,再去表格抓這些資料。
- 如果表很大、查詢只要少量資料,這個超快。
舉例: 沒索引時查年齡
SELECT * FROM students WHERE age = 25;
結果可能要讀 100 萬筆資料。有 B-TREE 索引時,系統可能只要讀 100 筆。
索引結構對效能的影響
索引會加速,是因為它們讓你不用掃全部資料。像表裡有幾百萬筆,索引會把它們組織好,查詢時只要讀幾個節點,不用全表掃一遍。
搞懂索引結構很重要。知道索引怎麼運作,你就能理解為什麼有些查詢慢、怎麼讓它變快。
還有,選對索引也很關鍵。要查範圍用 B-TREE。要查陣列或 JSONB 用 GIN。選錯索引反而會拖慢資料庫。
實際範例
來看看索引怎麼幫我們工作。
排序用的索引
CREATE INDEX salary_idx ON employees (salary);
SELECT * FROM employees ORDER BY salary;
有 B-TREE 索引時,PostgreSQL 可以直接從索引拿出排序好的資料,不用再另外排序。
範圍查詢用的索引
CREATE INDEX price_idx ON products (price);
SELECT * FROM products WHERE price BETWEEN 100 AND 500;
B-TREE 索引可以很快找到落在指定範圍內的資料。
常見問題與小陷阱
為什麼不是每個欄位都該加索引? 索引會佔硬碟空間,而且每次 insert、update、delete 都要更新索引結構,會拖慢這些操作。所以只要在常查詢的欄位加索引就好。
什麼時候索引沒用? 如果查詢會抓到大部分資料(像 WHERE true),PostgreSQL 會選擇 Seq Scan,因為讀索引節點沒什麼幫助。
GO TO FULL VERSION