許多開發者專注於 SQL 邏輯正確性,卻忽略不同寫法在大數據量下的效能落差。本文從索引設計、聯結條件、WHERE 子句三大面向,結合實測案例,示範如何讓查詢速度提升數十倍。
record:62 萬筆;card 7,896 筆;account 19 萬筆| 索引類型 | 範圍查詢 | GROUP BY | 多條件查詢 |
|---|---|---|---|
| date 非叢集 | 25 秒 | 55 秒 | 27 秒 |
| date 叢集 | 14 秒 | 28 秒 | 14 秒 |
| (place, date, amount) 組合 | 26 秒 | 27 秒 | < 1 秒 |
| (date, place, amount) 組合 | < 1 秒 | 11 秒 | < 1 秒 |
date)。-- 原始:僅用 card_no 聯結,I/O ≈ 595,907
SELECT SUM(a.amount) FROM account a, card b WHERE a.card_no = b.card_no
-- 優化:補上 account_no,優化器改選 card 為外層表,I/O ≈ 33,528
SELECT SUM(a.amount) FROM account a, card b
WHERE a.card_no = b.card_no AND a.account_no = b.account_no
原理:優化器根據聯結條件估算「外層表匹配行數 × 內層表單次查找頁數」,乘積最小者為最佳計畫。補全條件可讓優化器選擇更小的驅動表。
| 原寫法 (全表掃描) | 改寫後 (索引搜尋) |
|---|---|
substring(card_no,1,4)='5378' (13 秒) | card_no LIKE '5378%' (< 1 秒) |
amount/30 < 1000 (11 秒) | amount < 30000 (< 1 秒) |
convert(char(10),date,112)='19991201' (10 秒) | date = '1999/12/01' (< 1 秒) |
規則:將運算移至等號右側,保持左側欄位「乾淨」,使優化器能使用索引。
-- 慢:IN 轉為 OR,優化器用工作表去重,未用索引 (23 秒 → 62 萬筆時 220 秒)
SELECT COUNT(*) FROM stuff WHERE id_no IN ('0','1')
-- 快:拆分為兩條 UNION ALL,各自用索引 (3~4 秒)
SELECT COUNT(*) FROM stuff WHERE id_no='0'
UNION ALL
SELECT COUNT(*) FROM stuff WHERE id_no='1'
或封裝為預存程序,避免重複編譯與網路往返。
SQL 優化的本質:在結果正確前提下,寫出優化器能識別的語句,充分利用索引,減少 I/O,避免表掃描。應用層優化只是冰山一角,深層還涉及資源配置、網路、OS 調校。