查詢緩慢成因複雜,常見包含:缺乏索引、IO 瓶頸、鎖爭用、回傳過多資料、統計資訊過期、查詢寫法不佳等。本文彙整 47 條涵蓋架構、索引、T-SQL 寫法、監控與維護的實戰優化準則,助你系統化提升查詢效能。
架構與硬體層面
- 分離資料、記錄、索引至不同磁碟,提升平行 IO 能力;Tempdb 放置於高速儲存。
- 垂直/水平分割大型表,縮減單表尺寸(
sp_spaceuse 監控)。
- 擴充記憶體、升級 CPU、提升網路頻寬,硬體升級是最後手段但有時必要。
- OLTP 與 OLAP 分離,避免報表查詢干擾線上交易。
- 分散式分區檢視表 實現伺服器聯盟,支援大型 Web 站點擴展。
索引設計黃金法則
- 依查詢條件建立索引,優化存取路徑,限制結果集大小;填充因子採預設值 0 為宜。
- 索引鍵越窄越好,優先使用位元組數小的欄位;避免對低基數欄位(如性別)建單欄索引。
- 定期重建索引(
DBCC REINDEX、DBCC INDEXDEFRAG),收縮資料/記錄檔謹慎操作,大型資料庫禁用自動增長。
- 計算欄位符合條件時可建索引(SQL 2000+),需滿足確定性、非 LOB 型別、特定 SET 選項開啟。
T-SQL 寫法優化 20 條鐵律
- WHERE 子句限制回傳列數,避免全表掃描與鎖定升級。
- 慎用游標,改用集合式操作、臨時表、表變數、子查詢、CASE 表達式;若必須用,選擇
READ_ONLY、FAST_FORWARD 選項。
UNION ALL 優於 UNION(免排序去重),除非業務需去重。
- 避免不必要的
DISTINCT、ORDER BY,可在應用層處理。
- 使用
TOP N、SET ROWCOUNT 限制回傳/處理筆數。
- SARGable 原則:WHERE 條件避免函數運算、隱含轉換、
!=、NOT IN、LIKE '%xxx' 等導致索引失效的寫法;改用 EXISTS、BETWEEN、>= 等可利用索引的替代寫法。
IN 列表將高頻值前置,減少比較次數。
- 批次更新優於逐筆更新;
SELECT INTO 會鎖定系統表,改用明確 CREATE TABLE + INSERT SELECT。
GROUP BY 前用 WHERE 過濾,HAVING 僅過濾群組,降低排序成本。
- 臨時表慎用,優先考慮表變數或 CTE;必要時才對臨時表建索引。
- 事務最小化:只在必要時使用
BEGIN TRAN,縮短鎖持有時間。
OR 條件拆解為多查詢 + UNION ALL,嘗試匹配索引。
- 視圖嵌套增加解析開銷,優先用預存程序替代;單表查詢勿使用多表視圖。
COUNT(*) 效能較差,改用 EXISTS 或查詢系統目錄快速取得估計行數。
- 資料類型隱含轉換會導致索引失效,參數與欄位型別務必一致。
- 連接欄位優先選擇叢集索引鍵;SQL 2005+ 支援 Hash Join、Merge Join,大幅優於 2000 僅有的 Nested Loop Join。
- 綁定變數重用執行計劃,但「傾斜欄位」(如 90% 為同一值)需避免綁定變數窺探問題。
NOLOCK 提升並發但可能讀到髒資料:不可用於寫入依賴的查詢、頻繁頁分割的表;可用臨時表模擬 Oracle UNDO 機制作為替代。
- 叢集索引未建在順序鍵(如身分證號)會導致頁分割頻繁;重建索引後空洞消失反而加劇分割,需權衡填充因子。
- 統一 SQL 大小寫與格式,讓相同查詢重用計劃;避免超過 3 層巢狀子查詢,善用臨時表分解中間結果。
監控與維護關鍵指標
- Memory: Page Faults/sec 持續高 → 記憶體壓力。
- Processor: % Processor Time > 95% → CPU 瓶頸。
- Physical Disk: Current Disk Queue Length > 1.5~2 倍磁碟數 → IO 瓶頸。
- SQLServer: Cache Hit Ratio < 80% → 需增加記憶體(注意計數器為累計值,需觀察增量)。
- 使用
DBCC SHOW_STATISTICS、SET STATISTICS IO ON、查詢分析器實際執行計劃,鎖定前 20% 耗資源程式碼進行優化。
核心心法:執行計劃非固定不變,取決於 SQL 寫法清晰度與統計資訊新鮮度。簡單、可重用、統計資訊最新——是高效能查詢的三大基石。