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

SQL 執行效率優化 20 條鐵律:從 WHERE 條件順序到索引設計、分頁與動態 SQL 最佳實踐

     編輯:關於SqlServer

查詢重寫層面

  1. 拒絕子查詢入 WHERE:改用 JOIN / APPLY / CTE,避免重複執行
  2. 時間查詢不套函數:WHERE create_date >= '2023-01-01' AND create_date < '2023-02-01',禁用 TO_CHAR/YEAR/MONTH
  3. 高選擇性條件後置:Oracle/舊版優化器自下而上解析 WHERE,最強過濾條件寫最後 (現代優化器多無關,但習慣保持)
  4. FROM 最後的表 = 驅動表:多表 JOIN 時,小表/過濾後小結果集放最後 (Oracle 舊版 RBO);現代 CBO 看統計資料,但寫法仍建議小表在前
  5. 三表以上 JOIN 必有交叉表:A-B-C 連接,B 為交叉表 (被 A 和 C 都引用),B 應為驅動表
  6. 綁定變數:WHERE id = :b1 而非拼接字串,共用執行計畫、防注入
  7. WHERE 少用 OR:改 UNION ALL / IN / EXISTS
  8. EXISTS 替代 IN:WHERE EXISTS (SELECT 1 FROM B WHERE B.id = A.id) 通常優於 IN (SELECT id FROM B)
  9. NOT EXISTS 替代 NOT IN:NOT IN 遇 NULL 陷阱,NOT EXISTS 安全高效
  10. 索引欄不計算:WHERE sal*12 > 25000 → WHERE sal > 25000/12
  11. IN 替代 OR:WHERE loc_id IN (10,15,20)
  12. 索引欄避免 IS NULL/IS NOT NULL:B-tree 不存 NULL (Oracle),改用函數索引 / 位圖索引 / 預設值
  13. 組合索引必走前導欄:INDEX (A,B,C) 查詢必含 A,否則掃描
  14. UNION ALL 替代 UNION:無去重需求省排序
  15. 避免隱含轉換:WHERE empno = '123' (empno 為數值) → TO_CHAR(empno)='123' 索引失效,改 empno = 123
  16. != 導致掃描:改寫為範圍或 NOT EXISTS
  17. 優化 GROUP BY:只 SELECT 分組欄 + 聚合,盡早過濾 (WHERE > HAVING)
  18. LIKE 前導萬用字元不可用索引:'%YE' 掃描,'YE%' Seek → 全文檢索/反轉索引
  19. 拒絕複雜正則:LIKE '98___' → WHERE zipcode BETWEEN '98000' AND '98999' 走索引
  20. 明確 SELECT 欄位 + 表別名:禁用 SELECT *,減少 I/O、鎖、網路、解析開銷

索引設計鐵律

  • 高選擇性欄位優先建立 B-tree 索引
  • 組合索引順序:= 條件欄位在前,範圍條件在後
  • 覆蓋索引:INCLUDE 非鍵欄位,避免 Key Lookup
  • 過濾索引:WHERE status = 1 只索引活躍資料
  • 定期 UPDATE STATISTICS / REBUILD INDEX 消除碎片

分頁查詢最佳實踐

-- SQL Server 2012+ 標準語法
SELECT col1, col2
FROM dbo.BigTable
ORDER BY id
OFFSET @PageSize * (@PageNum - 1) ROWS
FETCH NEXT @PageSize ROWS ONLY;

-- 大表深分頁優化:延遲關聯
SELECT t.col1, t.col2
FROM (
    SELECT id FROM dbo.BigTable ORDER BY id
    OFFSET @PageSize * (@PageNum - 1) ROWS FETCH NEXT @PageSize ROWS ONLY
) p
JOIN dbo.BigTable t ON t.id = p.id;

動態 SQL 組裝規範

  • 參數化:sp_executesql @SQL, N'@id INT', @id
  • QUOTENAME 防注入:QUOTENAME(@Schema) + '.' + QUOTENAME(@Table)
  • 避免在迴圈中 EXEC,改用表值參數/臨時表批次處理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved