關聯式資料庫(引擎中立)
概覽
引擎中立的關聯式資料庫最佳實踐。原則與模式只需撰寫一次;僅在 SQL 方言有差異(MSSQL 與 MySQL/MariaDB 相比)的部分以內文標記或收集於方言速查表。最佳化目標為正確性,並以實證測量支援最小的變更。
使用時機
- 設計或審查 schema(表格、鍵、正規化、資料型別)。
- 新增或修正索引;診斷慢查詢或全表掃描。
- 讀取執行計畫以找出瓶頸。
- 選擇或排解交易隔離、鎖定或死結。
- 對大量結果集進行分頁;消除 N+1 存取。
- 規劃可安全上線的 schema 遷移。
不適用於: 引擎內部深入探討(儲存引擎內部如 InnoDB 緩衝池、供應商專屬功能、僅限 T-SQL 的結構、複寫/分片拓撲)。請使用該引擎的官方文件或專用的單一引擎技能。
工作流程
- 先確立背景脈絡。 哪個引擎 + 主要版本?讀寫比例、列數量、延遲目標、OLTP 或分析型。建議會因這些因素而改變。
- 僅閱讀以下各節連結的相關參考資料。
- 提出能解決問題的最小變更,並附帶權衡取捨。
- 用證據驗證——擷取變更前後的執行計畫與列/時間指標(請參閱
references/execution-plans.md),而非僅憑經驗法則。 - 對於正式環境,包含復原計畫與部署後驗證。
Schema 設計
- 明確建模關聯;從正規化(3NF/BCNF)開始,僅在有實證理由時才反正規化。每個表格都需要穩定的主鍵。
- 選擇最狹窄的正確資料型別;在 schema 層級(NOT NULL、UNIQUE、CHECK、FK)而非僅在應用程式碼中約束無效狀態。
參考資料:normalization · keys-and-constraints · data-types
索引
- 根據選擇性(而非猜測)為
WHERE、JOIN和ORDER BY中使用的欄位建立索引。複合索引順序:先放相等條件欄位,再放範圍/排序欄位(最左前綴規則)。範圍述詞會阻止索引對後續欄位生效。 - 涵蓋索引可避免資料表查詢。審查並刪除未使用/重複的索引;每個索引都會增加寫入負擔。
參考資料:indexing · composite-indexes
查詢最佳化
- 保持述詞為 SARGable——不要在
WHERE中對已索引欄位使用函式/隱含轉型。只選取需要的欄位。在不需要去重時,偏好使用EXISTS而非IN (子查詢)、UNION ALL而非UNION,並批次處理大量寫入。 - 使用 keyset(游標)分頁而非大型
OFFSET。透過批次或 JOIN 消除 N+1。
參考資料:query-optimization · execution-plans · pagination
交易與鎖定
- 保持交易簡短;在交易外部執行 I/O 和慢速工作。以一致的順序存取列以避免死結;預期死結並以退避重試。
- 了解你的引擎的預設隔離層級(因引擎而異)以及每個層級允許的異常。刻意使用鎖定讀取(
FOR UPDATE),而非習慣性使用。
參考資料:transactions-and-isolation · locking-and-deadlocks
遷移與 DDL
- 盡量使 schema 變更為新增優先且向後相容;擴充 → 回填 → 收縮。大型/會鎖定的 DDL 需要線上策略和復原路徑。
參考資料:migrations-and-ddl
引擎方言差異
自動遞增、識別符號引用、分頁、upsert、字串函式、目前時間、EXPLAIN 和隔離預設值在引擎之間都有差異。在撰寫可攜式 SQL 之前,請確認目標引擎的語法。
參考資料:engine-dialect-cheatsheet
防護措施
- 偏好實證(執行計畫、指標)而非概括性規則。
- 當行為取決於引擎時,請明確說明引擎與主要版本。
- 在破壞性操作(DROP/DELETE/TRUNCATE 或任何不可逆遷移)前,必須取得明確的人工核可。務必先確認存在備份。