前言
資料庫設計是系統成敗關鍵:50% 業務理解 + 50% 軟體實作,而軟體實作中 25% 資料庫設計 + 25% 程式碼。本文彙整 60 個實戰驗證的設計法則,分五大面向。
第一部分:設計前準備 (12 條)
- 調研現有系統:即使重寫,舊系統流程/報表/痛點是需求寶庫。
- 定義命名規範:表名單複數統一、別名規則 (4 字元)、欄位前後綴 (_PK, _FK, _ID, _CD, _NM, _DT, _AMT, _FLG)、索引/限制式命名 (PK_, FK_, IX_, CK_, DF_)。
- 選擇合適工具:PowerDesigner / ERwin / SQLDBM 支援版本控制、逆向工程、多平台腳本產生。
- 明確業務範疇與優先序:核心交易表優先,報表/日誌表次之。
- 識別核心實體與關係:繪製 ER 圖,驗證基數 (1:1, 1:N, M:N)。
- 定義資料字典:欄位中文名、型別、長度、可空、預設值、驗證規則、業務說明。
- 規劃分區/歸檔策略:大表 (交易流水、日誌) 預留分區鍵、歸檔流程。
- 評估並發與鎖定模式:熱點表採樂觀鎖/版本號、縮短交易範圍。
- 安全性分級:敏感欄位 (身分證、薪資、密碼雜湊) 標記加密/遮罩/審計。
- 國際化考量:字串欄位預留 Unicode (NVARCHAR)、排序規則、時區處理。
- 文件化決策理由:每個關鍵設計選擇 (為何用代理鍵、為何非正規化) 留下紀錄。
- 評審機制:DBA、架構師、資深開發聯審,簽署基線版本。
第二部分:資料表與欄位設計 (24 條)
- 單一職責:一表一核心實體,避免大寬表。
- 代理主鍵 (Surrogate Key):業務鍵 (身分證、訂單號) 不做 PK,用 INT/BIGINT IDENTITY 或 UUID。
- 統一主鍵命名:
TableName_ID 或 ID,外鍵同名,利於 JOIN 寫法一致。
- 外鍵務必建立:資料庫層級
FOREIGN KEY 保證參考完整性,防止髒資料。
- 非空預設:業務必填欄位
NOT NULL + DEFAULT,減少應用層判斷。
- 精確型別:金額用
DECIMAL(18,4),非浮點;日期用 DATE/DATETIME2;布林用 BIT;大文本用 VARCHAR(MAX)/NVARCHAR(MAX)。
- 避免過度正規化:頻繁 JOIN 的查閱表 (狀態、類別) 可適度非正規化冗餘代碼/名稱。
- 審計欄位標準化:
CreatedBy, CreatedAt, UpdatedBy, UpdatedAt, Version/RowVersion 所有表統一。
- 軟刪除:
IsDeleted BIT NOT NULL DEFAULT 0 + 過濾索引 WHERE IsDeleted = 0,避免物理刪除破壞關聯。
- 枚舉值表驅動:狀態、類型、代碼建立字典表,前端下拉選單動態載入,避免硬編碼。
- 大欄位垂直分表:BLOB/長文本/低頻欄位移至擴展表 (1:1),主表保持窄而快。
- 中繼表命名:M:N 關係表命名
EntityA_EntityB,PK 為雙外鍵組合。
- 歷史/快照表:重要業務變更寫入歷史表 (觸發器/CDC),支援時點查詢。
- 避免保留字:欄位名不使用
Order, Group, Key, Index, Type, Status 等保留字。
- 一致性縮寫:
Qty, Amt, Cnt, Seq, Ref, Config, Log, Tmp, Bak 全專案統一。
- 計算欄持久化:頻繁查詢的衍生欄位用
PERSISTED COMPUTED COLUMN 或索引視圖。
- 檢查約束 (CHECK):資料域驗證 (如
Age BETWEEN 0 AND 150) 下推資料庫層。
- 唯一約束 (UNIQUE):業務唯一鍵 (Email、手機、身分證) 必加
UNIQUE 索引。
- 預設值集中管理:系統級預設值 (如當前語言、時區) 用函數/視圖封裝,避免硬編碼。
- 索引策略:
WHERE/JOIN/ORDER BY/GROUP BY 欄位建索引;INCLUDE 覆蓋查詢;避免過度索引 (寫入放大)。
- 分區對齊:分區表索引必須對齊分區函數,利於切換/歸檔。
- 壓縮策略:歷史分區啟用
DATA_COMPRESSION = PAGE,節省空間與 I/O。
- 檔案群組規劃:資料/索引/記憶體優化表/大物件分置不同檔案群組,配置不同磁碟。
- 統計資料自動更新:
AUTO_UPDATE_STATISTICS ON,大表啟用 AUTO_UPDATE_STATISTICS_ASYNC。
第三部分:鍵選擇與索引 (10 條)
- 代理鍵優先:INT IDENTITY (4 bytes) < BIGINT (8 bytes) < UUID (16 bytes) — 選最小滿足量級者。
- 叢集索引選擇:窄、唯一、遞增、靜態 — 代理鍵通常最佳;避免 GUID/複合鍵/頻繁更新欄位。
- 非叢集索引覆蓋:
INCLUDE 欄位滿足查詢無需回表 (Key Lookup)。
- 過濾索引:
WHERE IsDeleted = 0、WHERE Status = 'Active' 大幅縮小索引體積。
- 索引欄位順序:等值查詢欄位在前、範圍查詢在後、選擇性高在前。
- 避免隱含轉換:
WHERE VarcharCol = 123 導致索引失效,參數化查詢傳正確型別。
- 統計資料維護:大表排程
UPDATE STATISTICS ... WITH FULLSCAN,配合 sp_updatestats。
- 碎片整理:
REBUILD (離線/Online) vs REORGANIZE,依碎片率 30%/10% 門檻決定。
- 缺失索引 DMV:定期查詢
sys.dm_db_missing_index_* 發現潛在索引,人工評估後建立。
- 索引使用率監控:
sys.dm_db_index_usage_stats 找出未用索引 (讀取=0、寫入>0) 候選移除。
第四部分:資料完整性與品質 (8 條)
- 資料庫層級約束優先:PK/FK/UK/CK/DEFAULT/DF 盡可能在 DDL 定義,不依賴應用層。
- 觸發器慎用:僅用於跨表業務規則、審計、同步;避免複雜邏輯、遞迴、發送郵件。
- 交易邊界最小化:只包含必要寫入操作,查詢移出交易,減少鎖持有時間。
- 隔離等級選擇:預設
READ COMMITTED;報表用 READ COMMITTED SNAPSHOT (RCSI) 或 SNAPSHOT 避免阻塞。
- 死鎖處理:統一存取順序 (表 A → 表 B)、設定
DEADLOCK_PRIORITY LOW 於低優先交易、重試邏輯。
- 資料遮罩/加密:Dynamic Data Masking (非生產)、Always Encrypted (敏感欄位)、TDE (靜態)。
- 匿名化測試資料:生產資料導入測試環境前必經脫敏 (姓名、身分證、電話、金額打散)。
- 定期資料品質檢核:孤兒記錄、重複業務鍵、違反 CHECK 約束、NULL 比例異常自動報警。
第五部分:實戰技巧與避坑 (6 條)
- 大量刪除分批次:
DELETE TOP (5000) ... 迴圈 + WAITFOR DELAY '00:00:01' 避免鎖升級、記錄檔暴漲。
- 大量匯入最小化記錄:
BULK INSERT / bcp + TABLOCK + 簡單復原模式 + 無索引/先建索引。
- 動態 SQL 參數化:
sp_executesql @sql, N'@p1 INT', @p1 而非字串拼接,防注入 + 計畫重用。
- 版本號樂觀鎖:
UPDATE T SET Col=Val, Ver=Ver+1 WHERE ID=@id AND Ver=@oldVer,@@ROWCOUNT=0 表示衝突。
- 查詢提示最後手段:
FORCE ORDER, LOOP JOIN, HASH JOIN, INDEX(...) 僅在確證優化器錯誤且無其他優化空間時使用。
- 變更管理流程:所有 DDL/DML 結構變更經由票證、審核、測試、回滾腳本、上線窗口、事後驗證。
結語
這 60 條法則並非教條,而是經驗提煉的「檢查清單」。專案初期投入設計評審成本,可節省後期 10 倍以上的重構與救火成本。建議列印張貼團隊工位,融入 Code Review 與架構評審標準動作。