首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

SQL 語句效能優化完整指南:34 條核心準則與最佳實踐

     編輯:MySQL 綜合教學

SQL 語句效能優化完整指南:34 條核心準則與最佳實踐

隨著資料量增長,SQL 效能優化成為系統穩定性的關鍵。優質 SQL 與劣質 SQL 執行速度可相差數百倍。本文整理 34 條經過生產環境驗證的優化準則,涵蓋運算子優化、索引利用、查詢重寫、架構設計等維度,助你寫出高效能 SQL。

一、運算子與條件優化

1. IN vs EXISTS

  • IN 缺點:Oracle 需轉換為多表連接或先執行子查詢,多一轉換過程
  • 推薦:業務密集 SQL 改用 EXISTS 替代 IN
  • NOT IN 禁用:無法使用索引,必須改用 NOT EXISTS 或 LEFT JOIN ... WHERE IS NULL

2. IS NULL / IS NOT NULL

  • 索引不儲存 NULL 值,任何包含 NULL 的複合索引欄位都會從索引排除
  • 替代方案:IS NOT NULL → > 0 或 > '';設計階段設定 NOT NULL DEFAULT ''

3. 比較運算子優化

原寫法優化寫法原理
A > 2A >= 3直接定位到 3,避免先找 2 再比較
LIKE '%5400%'LIKE 'X5400%' OR LIKE 'B5400%'前導萬用字元無法用索引,指定前綴可用範圍索引
col IS NOT NULLcol > 0 / col > ''啟用索引掃描

4. UNION vs UNION ALL

  • UNION:合併後排序去重,大資料量可能用到磁碟排序
  • UNION ALL:直接合併返回,效能大幅提升
  • 原則:業務允許重複或確定無重複時,優先用 UNION ALL

5. 列連接導致索引失效

-- 錯誤:連接列無法用索引
WHERE first_name || '' || last_name = 'Bill Clinton'

-- 正確:拆分條件
WHERE first_name = 'Bill' AND last_name = 'Clinton'

6. ORDER BY 優化

  • 避免在 ORDER BY 中使用非索引欄位或運算表達式
  • 為排序欄位建立索引,或重寫查詢使用索引順序

7. NOT 邏輯優化

-- 低效:無法用索引
WHERE status <> 'INVALID'
WHERE NOT (status = 'VALID')

-- 高效:拆分為 OR 條件(可用索引)
WHERE salary < 3000 OR salary > 3000

二、SQL 寫作習慣影響效能

8. 統一 SQL 寫法利用共享記憶體

  • Oracle SGA 依 SQL 字串完全匹配快取執行計畫
  • 大小寫、空格、表擁有者前綴不一致會產生多份計畫,浪費記憶體
  • 規範:團隊統一 SQL 格式化標準(大寫關鍵字、固定縮排、加表別名)

9. WHERE 條件順序影響 CPU 耗用

  • 過濾率高(資料少)的條件優先寫在前面
  • 範例:xh_bz=1 AND dy_dj='1KV以下' 優於反序(0.5% vs 99% 過濾率)

10. 表連接順序

  • 無統計資訊時,Oracle 按 FROM 子句順序連接
  • 小表優先連接大表,減少中間結果集
  • 有統計資訊時優化器自動調整

三、索引利用核心原則

11. 函數/運算導致索引失效

失效寫法優化寫法
SUBSTR(hbs_bh,1,4)='5400'hbs_bh LIKE '5400%'
TRUNC(sk_rq)=TRUNC(SYSDATE)sk_rq >= TRUNC(SYSDATE) AND sk_rq < TRUNC(SYSDATE)+1
ss_df+20 > 50ss_df > 30
'X' || hbs_bh > 'X5400021452'hbs_bh > '5400021542'

12. 隱式型別轉換殺手

-- 字串欄位比較數字,觸發 TO_NUMBER 導致索引失效
WHERE hbs_bh = 5401002554

-- 修正:加上引號
WHERE hbs_bh = '5401002554'

13. 複合索引最左前綴原則

  • 複合索引 (A,B,C) 僅當 WHERE 條件包含 A 時才會被使用
  • 僅引用 B 或 C 會導致全表掃描

四、進階優化技巧(14-34)

#優化準則關鍵點
14選擇最高效表順序(RBO)FROM 右到左解析,記錄最少的表放最後(基礎表)
15WHERE 連接條件優先於過濾條件表連接寫在前,過濾率高的條件寫在後
16避免 SELECT *解析 * 需查資料字典,列出具體欄位
17減少資料庫存取次數合併查詢、使用陣列繫結、調大 ARRAYSIZE
18使用 DECODE/CASE 減少重複掃描單次掃描完成多條件聚合
19整合無關聯簡單查詢多個獨立查詢合併為一個
20刪除重複記錄用 ROWIDDELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO)
21TRUNCATE 替代 DELETE(全表清空)不產生回滾段,極速執行,不可回滾
22適度提交 COMMIT釋放回滾段、鎖、redo log buffer
23WHERE 替代 HAVING分組前過濾優於分組後過濾
24減少子查詢表存取改用 JOIN 或合併條件
25善用內部函數提升效率如分析函數、窗口函數替代複雜子查詢
26使用表別名減少解析時間、避免欄位歧義
27EXISTS 替代 IN / NOT EXISTS 替代 NOT IN子查詢效能顯著提升
28識別低效 SQL查詢 V$SQLAREA,關注 BUFFER_GETS/EXECUTIONS、HIT_RATIO
29索引維護與重建定期 ALTER INDEX REBUILD,移除無用索引
30EXISTS 替代 DISTINCT(一對多查詢)滿足條件立即返回,避免排序去重
31SQL 關鍵字大寫減少解析器小寫轉大寫開銷
32Java 代碼少用 + 連接字串使用 StringBuilder 或 PreparedStatement
33避免索引列用 NOT導致全表掃描
34避免索引列運算SAL * 12 > 25000 → SAL > 25000/12

五、特殊場景優化補充

35. >= 替代 >

-- 高效:直接跳到 4
WHERE deptno >= 4
-- 低效:先定位 3 再掃描
WHERE deptno > 3

36. UNION 替代 OR(索引欄位)

-- 高效:兩次索引掃描合併
SELECT ... WHERE loc_id = 10 UNION SELECT ... WHERE region = 'MELBOURNE'
-- 低效:全表掃描
SELECT ... WHERE loc_id = 10 OR region = 'MELBOURNE'

37. IN 替代多個 OR

WHERE loc_id IN (10,20,30)  -- 通常優於多個 OR

38. 避免索引列 IS NULL/IS NOT NULL

  • 單列索引:NULL 不進索引
  • 複合索引:全 NULL 不進索引,部分 NULL 進索引
  • 唯一索引允許多筆全 NULL 記錄

39. WHERE 替代 ORDER BY

-- 低效:ORDER BY 非索引欄位
SELECT dept_code FROM dept ORDER BY dept_type
-- 高效:WHERE 條件啟用索引
SELECT dept_code FROM dept WHERE dept_type > 0

40. 避免隱式型別轉換

-- 字串索引列比較數字 → TO_NUMBER(索引列) → 索引失效
WHERE emp_type = 123
-- 修正:顯式轉換常數
WHERE emp_type = '123'

41. 30% 門檻法則

  • 查詢資料超過表總筆數 30%,全表掃描可能優於索引掃描
  • 但通常情況索引仍快數倍至數千倍

42. 避免耗資源操作

  • DISTINCT、UNION、MINUS、INTERSECT、ORDER BY 觸發排序
  • DISTINCT 一次排序,其他至少兩次
  • 可用 EXISTS、ROW_NUMBER() 重寫

43. GROUP BY 優化

-- 低效:分組後再過濾
SELECT job, AVG(sal) FROM emp GROUP BY job HAVING job IN ('PRESIDENT','MANAGER')
-- 高效:分組前過濾
SELECT job, AVG(sal) FROM emp WHERE job IN ('PRESIDENT','MANAGER') GROUP BY job

六、總結:優化檢查清單

  1. ✅ 是否避免了 NOT IN、IS NULL、列運算、隱式轉換?
  2. ✅ WHERE 條件順序是否將高選擇性條件前置?
  3. ✅ 是否使用 UNION ALL 替代 UNION?
  4. ✅ 複合索引是否遵循最左前綴?
  5. ✅ 是否將 HAVING 改為 WHERE?
  6. ✅ 大表查詢是否避免 SELECT *?
  7. ✅ SQL 格式是否統一(利用計畫快取)?
  8. ✅ 是否定期分析執行計畫與 V$SQLAREA 識別慢 SQL?

核心心法:優化不是背誦規則,而是理解優化器決策邏輯——「讓索引能用、讓掃描少讀、讓排序不發生、讓計畫可複用」。每條 SQL 都要用 EXPLAIN 驗證,實測才是硬道理。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved