| 索引策略 | 範圍查詢 (date+amount) | GROUP BY date | 篩選 (date+place) | 分析 |
|---|---|---|---|---|
| date 非叢集 | 25 秒 | 55 秒 | 27 秒 | 大量重複值導致書籤查詢退化為掃描 |
| date 叢集 | 14 秒 | 28 秒 | 14 秒 | 資料物理有序,範圍查詢僅掃描相關頁面 |
| (place,date,amount) 組合 | 26 秒 | 27 秒 | <1 秒 | 前導欄 place 未用於前兩查詢,索引失效 |
| (date,place,amount) 組合 | <1 秒 | 11 秒 | <1 秒 | 前導欄 date 滿足所有查詢,形成索引覆蓋,最優 |
card (7,896 筆, card_no 非叢集) JOIN account (191,122 筆, account_no 非叢集)
-- 僅 JOIN card_no:20 秒
SELECT SUM(a.amount) FROM account a, card b WHERE a.card_no = b.card_no;
-- 加上 account_no:<1 秒
SELECT SUM(a.amount) FROM account a, card b
WHERE a.card_no = b.card_no AND a.account_no = b.account_no;
原理:優化器依連接條件估算 I/O 成本。
條件 1:外部 account (22,541 頁) + 191,122 × 3 = 595,907 I/O。
條件 2:外部 card (1,944 頁) + 7,896 × 4 = 33,528 I/O → 優化器選擇最佳路徑。
結論:提供完整連接條件 (含所有索引欄位),讓優化器找到真正最佳計畫。
| 原寫法 (全表掃描) | 改寫後 (索引搜尋) | 原理 |
|---|---|---|
SUBSTRING(card_no,1,4)='5378' (13 秒) | card_no LIKE '5378%' (<1 秒) | 函數/運算在左側 → 隱性轉換 → 掃描 |
amount/30 < 1000 (11 秒) | amount < 30000 (<1 秒) | 運算移至右側常數,保持 SARGable |
CONVERT(char(10),date,112)='19991201' (10 秒) | date = '1999/12/01' (<1 秒) | 避免轉換函數,直接比對日期常值 |
-- 慢:IN 轉為 OR 策略 → 建立暫存工作表 → 23 秒 (20 萬筆) / 220 秒 (62 萬筆)
SELECT COUNT(*) FROM stuff WHERE id_no IN ('0','1');
-- 快:拆分查詢 + UNION ALL 或預存程序彙總 → 3-4 秒
SELECT COUNT(*) FROM stuff WHERE id_no = '0';
SELECT COUNT(*) FROM stuff WHERE id_no = '1';
IN/OR 常觸發「OR 策略」:建立暫存表、去重複,無法使用索引。若值不重複,拆分為多查詢再彙總。
IN/OR 拆分或改用 UNION ALL / 暫存表 / 資料表值參數。SQL 優化是系統工程:應用層寫法 → 資料庫層索引/統計 → 作業系統/硬體資源。從寫法入手,投資報酬率最高。