SQL 索引 Index

Posted by Adam on August 24, 2022
在 Oracle 中,建立索引時使用「一個引數」與「兩個(或多個)引數」,本質上的差別在於你是建立 **「單一欄位索引」** 還是 **「複合索引 (Composite Index)」**。 這不僅僅是欄位多寡的問題,還會直接影響到資料庫如何「切西瓜」找到你要的資料。 --- ### 1. 單一欄位索引 (Single-Column Index) **語法:** `CREATE INDEX idx_name ON table_name (event_code);` * **結構:** 索引樹只根據 `event_code` 排序。 * **適用情境:** 你的 `WHERE` 條件通常只單獨查詢這個欄位。 * **缺點:** 如果你同時查詢 `event_code` 和 `cust_id`,資料庫雖然能用索引找到 `event_code`,但還是得回表 (Table Access By Index ROWID) 去確認 `cust_id` 是否符合,這在大表(如你的三千萬筆資料)會產生額外的 I/O 消耗。 --- ### 2. 複合索引 (Composite/Concatenated Index) **語法:** `CREATE INDEX idx_name ON table_name (event_code, cust_id);` * **結構:** 索引樹會先依照 `event_code` 排序,在相同的 `event_code` 內,再依照 `cust_id` 排序。 * **優點 (Index Skip Scan / Covering Index):** * **一魚兩吃:** 如果你的 SQL 同時過濾這兩個欄位,資料庫可以直接在索引樹中精確定位,不需要回表。 * **前綴特性:** 這個索引也可以被單獨查詢 `event_code` 的 SQL 使用。 * **缺點:** 索引體積較大,且**欄位順序很重要**。 --- ### 3. 關鍵差異對比 | 特性 | 單一索引 `(A)` | 複合索引 `(A, B)` | | :--- | :--- | :--- | | **查詢 `WHERE A=...`** | ✅ 支援 | ✅ 支援 (利用前綴) | | **查詢 `WHERE A=.. AND B=..`** | ⚠️ 慢(需回表找 B) | 🚀 極快 (Index Only / Filtered) | | **查詢 `WHERE B=...`** | ❌ 不支援 | ⚠️ 通常不支援 (除非 Skip Scan) | | **索引體積** | 較小 | 較大 | --- ### 4. 針對您三千萬筆資料的實務建議 從您之前的截圖看到您想建的是 `(event_code, cust_id)`: 1. **欄位順序:** 應該把 **「篩選性高(值比較不重複)」** 的欄位放在前面。如果 `event_code` 只有 10 種,但 `cust_id` 有 100 萬種,通常建議將 `cust_id` 放在前面,除非你大部分的查詢都一定會帶 `event_code`。 2. **覆蓋查詢 (Covering Index):** 如果你的 SQL 是 `SELECT count(*) ... WHERE event_code = :1 AND cust_id = :2`,因為索引裡已經包含了這兩個欄位,Oracle 甚至**完全不需要讀取實體資料表**,直接在索引裡就能給出答案,速度會從「秒級」變成「毫秒級」。 ### 💡 結論 如果您常同時使用這兩個欄位查詢,**建立「兩個引數」的複合索引是絕對正確的選擇**。它比建兩個單一索引更節省空間,且對這類查詢的效能提升最明顯。