前言
資料庫效能問題多源於設計階段的決策失誤。本文彙整 20 項實戰經驗,涵蓋工具掌握、游標迷思、正規化、索引策略、交易處理、鎖死預防、參數化查詢、大量資料匯入、並行控制等面向,助你避開常見陷阱,打造高效可維護的 SQL Server 系統。
1. 精通你的工具:T-SQL 指令與工具箱
花一個週末瀏覽所有 T-SQL 指令,建立「有這個功能」的心智索引,需要時再查 MSDN 確切語法。不知工具無法善用工具。
2. 堅決拒絕游標
- 游標逐列處理 = 重複執行 SELECT,10,000 列 = 10,000 次 SELECT。
- 佔用記憶體、長時間鎖定、效能極差,導致 DBA 優化失效。
- 集合思維:用單一 `INSERT/UPDATE/DELETE` 陳述式處理批次作業。
- 真實案例:10 萬筆資料,游標存儲程序 40 分鐘 → 集合改寫 10 秒。
- 極少數必須逐列邏輯時,改用用戶端程式迴圈處理並批次更新。
3. 堅持正規化設計
- 反正規化理由通常是「效能」或「懶惰」,後者遲早付出代價。
- DBMS 核心優化針對正規化結構;過早反正規化常使系統更慢。
- 先正規化,再針對經證實的熱點進行最小範圍去正規化。
4. 禁止 SELECT *
- 減少網路頻寬與記憶體耗用。
- 避免結構變更導致應用程式中斷。
- 給最佳化器機會採用覆蓋索引 (Covering Index)。
5. 索引策略:瞭解存取模式再建立
- 每個索引加速 SELECT 但拖慢 INSERT/DELETE/UPDATE (維護成本)。
- 關鍵問題:該表主要承擔何種操作?
- 刪除/更新常含 WHERE 子查詢,同樣受索引影響。
6. 低選擇性欄位勿建索引 (如「性別」)
- 索引本質是將表依值域劃分區塊;性別僅分「男/女」,百萬筆資料每塊仍 50 萬筆,掃描成本極高。
- 索引維護成本 > 查詢收益。
- 複合索引欄位順序:選擇性由高到低 (如 `姓名 + 省份 + 性別`)。
7. 善用交易 (Transaction)
- 長時間查詢務必包裹交易,系統異常時保護資料一致性。
- 經驗法則:任何多陳述式邏輯單元皆應有交易邊界。
8. 固定鎖定順序預防死結
- 所有存儲程序遵循相同資料表鎖定順序 (如先 A 後 B)。
- 單一存儲程序違反順序即可能觸發死結,且難以在測試環境重現。
- 設計階段即定義鎖定階層並強制執行。
9. 拒絕大結果集回傳前端
- 10 萬筆下拉選單 = 使用者詛咒開發者。
- UI 層面解決:分頁、搜尋、最多 100-200 筆顯示。
10. 優先使用用戶端游標
11. 必須使用參數化查詢
- 單引號跳脫治標不治本,仍有其他字元注入風險,且破壞計畫快取重用。
- 參數查詢徹底解決注入、編碼、計畫重用三大問題。
12. 開發階段使用真實資料量測試
- 硬碟便宜,效能問題上線後修復成本指數級增長。
- 測試資料應模擬生產環境資料分佈、索引碎片、統計資料狀態。
13. 大量資料匯入勿用 INSERT
- 使用 BCP、BULK INSERT 或 SSIS,效率高數量級。
14. 關注連線逾時設定
- 預設 15-30 秒,長時間查詢需調整 `CommandTimeout`。
- 資料增長導致查詢時間漸增,需定期檢視。
15. 處理並行更新衝突 (失去更新問題)
- 加入 `timestamp` / `rowversion` 欄位,更新前比對版本號。
- 版本不符 → 提示使用者重新載入並合併修改。
16. 細節表插入勿用 SELECT MAX(ID)
- 併發下會產生重複鍵值。
- 改用 `SCOPE_IDENTITY()`、`IDENT_CURRENT()`、`@@IDENTITY` (觸發器環境下慎用)。
17. 能不 NULL 就不 NULL
- 每列額外 1 位元組儲存 NULL 位圖,查詢需額外判斷邏輯。
- 業務真正允許「未知」才設 NULL;否則用預設值或正規化拆分關聯表。
- 反例:`CustomerName1/2/3, Address1/2/3...` 應拆分為客戶-聯繫人關聯表。
18. 避免 TEXT / NTEXT / IMAGE 型別
- 查詢困難、效能差、空間浪費。
- `VARCHAR(MAX)` / `NVARCHAR(MAX)` / `VARBINARY(MAX)` 為現代替代方案 (SQL 2005+)。
19. 減少暫存表使用
- 子查詢、CTE、表值變數 (Table Variable) 多為更佳替代。
- 暫存表在連線池環境下生命週期管理複雜,易造成競爭。
20. 善用查詢分析器與執行計畫
- 圖形化執行計畫、統計資料 IO/Time、Missing Index 建議是調優三大利器。
附贈:參考完整性 (RI) 的價值
- 定義 PK、UK、FK 讓引擎自動維護資料一致性,省去應用層大量防禦性程式碼。
總結
資料庫開發的核心差異在於「集合思維」與「預防性設計」。內化上述 20 項原則,配合持續的效能基準測試與執行計畫分析,能顯著降低上線風險與長期維護成本。