HP LH II / 330MHz / 128MB / Sybase 11.0.3(原理通用於SQL Server)。record表62萬行。
| 索引方案 | 範圍查詢1 | GROUP BY | 複合條件查詢 |
|---|---|---|---|
| date非叢集 | 25秒 | 55秒 | 27秒 |
| date叢集 | 14秒 | 28秒 | 14秒 |
| (place,date,amount)複合 | 26秒 | 27秒 | <1秒 |
| (date,place,amount)複合 | <1秒 | 11秒 | <1秒 |
place,前兩查詢未引用 → 索引失效;方案4前導date,所有查詢受益並形成索引覆蓋(查詢欄位全在索引中) → 極致效能。card(7896行,card_no非叢集)JOIN account(19萬行,account_no非叢集)。
-- 僅連接card_no:20秒(外層account掃描22541頁 + 19萬×3頁書籤查找)
SELECT SUM(a.amount) FROM account a, card b WHERE a.card_no = b.card_no
-- 增加account_no:<1秒(外層card掃描1944頁 + 7896×4頁書籤查找)
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成本估算公式:外層頁數 + 外層行數 × 內層單次查找頁數,乘積最小者勝出。
| 不可優化寫法 | 耗時 | 優化寫法 | 耗時 |
|---|---|---|---|
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秒 |
鐵律:WHERE子句對欄位的任何運算(函數、運算式、隱含轉換)都會導致索引失效、全表掃描。將運算移至等號右側,保持欄位「裸露」。
-- IN邏輯等價OR,優化器採「OR策略」:建臨時表+唯一索引去重 → 索引失效
SELECT COUNT(*) FROM stuff WHERE id_no IN ('0','1') -- 23秒(62萬行達220秒)
-- 拆分為兩查詢再相加:各用索引 → 3秒
SELECT COUNT(*) FROM stuff WHERE id_no='0'
SELECT COUNT(*) FROM stuff WHERE id_no='1'
或寫存儲過程拆分執行,避免工作表開銷。
SQL優化本質:在結果正確前提下,寫出優化器可識別的語句,充分利用索引,減少I/O,避免表掃描。應用層優化只是冰山一角,深層涉及資源配置、網路、OS調度。