核心概念

設計資料庫的本質是「把現實世界的事物,翻譯成電腦能夠儲存與查詢的結構」。在動手建表之前,有八個底層邏輯必須先搞清楚。

一、資料建模(Data Modeling)

任何資料庫設計都從三個問題開始:

  • 實體(Entity):你要記錄什麼東西?(用戶、訂單、商品)
  • 屬性(Attribute):每個東西有哪些欄位?(用戶有 id、name、email)
  • 關聯(Relationship):這些東西之間有什麼關係?(一個用戶有多筆訂單)

先在紙上畫清楚這三者,再開始建表,省去大量後期重構的麻煩。

二、主鍵與外鍵

  • Primary Key(主鍵):唯一識別一筆資料的欄位,通常是自增 id。每張表必有一個。
  • Foreign Key(外鍵):存放另一張表主鍵的欄位,用來建立表與表之間的關聯。

例如 orders 表中的 user_id 就是外鍵,指向 users 表的 id

三、正規化(Normalization)

核心原則:同一份資料只存在一個地方

若客戶姓名同時存在訂單表和出貨表,一旦客戶改名,兩處都要更新,容易造成不一致。正規化把重複資料抽出去,讓修改只需要動一個地方。

常用到第三正規化(3NF),實務上不必追求完美正規化,視效能需求可以適度反正規化(denormalize)。

四、關聯類型

類型 說明 範例 實作方式
1:1 一對一 用戶 ↔ 個人檔案 外鍵加 UNIQUE
1:N 一對多 用戶 → 多筆訂單 訂單表加 user_id 外鍵
N:N 多對多 訂單 ↔ 商品 需要中間表(pivot table)

N:N 中間表(如 order_items)通常同時包含兩張表的主鍵,可附加數量、價格等額外欄位。

五、CRUD 操作

Create / Read / Update / Delete——所有資料庫互動的基本單位,對應 SQL 的 INSERT / SELECT / UPDATE / DELETE。設計 schema 時要同時想清楚這四種操作的使用頻率,會影響索引策略。

六、索引(Index)

索引讓資料庫不必掃描全表就能定位資料,類似書本的目錄。常在 WHEREJOINORDER BY 的欄位加索引。

注意取捨:索引加速讀取,但每次 INSERT / UPDATE 都需要同步更新索引,因此會拖慢寫入。高頻寫入的表不要濫加索引。

七、交易(Transaction)與 ACID

一組操作打包成一個交易,保證要嘛全部成功,要嘛全部回滾。ACID 四個屬性:

屬性 意義
Atomicity(原子性) 全成功或全失敗
Consistency(一致性) 操作前後資料符合業務規則
Isolation(隔離性) 並發交易互不干擾
Durability(持久性) 提交後的資料不會因當機消失

典型案例:轉帳時「扣款」與「入帳」必須在同一個 transaction 內,否則可能扣款成功但入帳失敗。

八、SQL vs NoSQL 的選擇邏輯

場景 選擇 代表工具
資料有明確結構、需要複雜查詢、強一致性 SQL(關聯式) PostgreSQL、MySQL
資料結構彈性、讀多寫多、需要水平擴展 NoSQL(文件/KV/圖) MongoDB、Redis、DynamoDB

兩者不互斥,許多系統混用:PostgreSQL 處理核心業務資料,Redis 做快取,MongoDB 存 log。

關鍵要點

  • 建模先行:先畫 ER Diagram,確定實體、屬性、關聯後再建表
  • 主鍵每張表都必須有;外鍵用來建立表間關聯,不是可選項
  • 正規化的目標是「單一事實來源」,不是追求最高正規化等級
  • N:N 關係必須透過中間表實現,不要用陣列欄位硬存
  • 索引是讀寫取捨,依實際查詢模式決定加在哪
  • 凡涉及「多步驟且不可分割」的操作,一律用 transaction 包起來
  • 選 SQL 還是 NoSQL,看的是「資料結構彈性需求」與「一致性強度要求」

實務應用

設計一個電商後台的最小 schema 可以這樣思考:

  1. 列出實體:用戶、商品、訂單、訂單明細
  2. 確認關聯:用戶 1:N 訂單、訂單 N:N 商品(透過訂單明細)
  3. 每個實體加主鍵 id,關聯用外鍵連接
  4. orders.user_idorder_items.order_idorder_items.product_id 加索引
  5. 結帳流程(扣庫存 + 建訂單)放進同一個 transaction

這五步走完,schema 的邏輯正確性就有基本保障。

延伸觀點

正規化不是終點,反正規化是刻意決策

正規化與反正規化並非對立,而是針對不同工作負載的工具。10K 用戶下有效的 schema,在千萬用戶時可能成為瓶頸。OLTP 系統(高頻交易)傾向正規化保障一致性,分析型系統(讀多寫少)則常反正規化減少 JOIN 成本。實務原則:先正規化設計,再根據真實效能數據決定哪裡值得反正規化,不要未量測就預先優化。

索引的隱藏成本:B-tree 頁面分裂

索引的寫入開銷不只是「更新索引樹」。B-tree 索引以固定大小的頁面儲存資料,頁面寫滿後插入新資料會觸發「頁面分裂」,產生額外磁碟操作與碎片化。一個常被忽略的細節:UUID v4(隨機)作為主鍵,隨機插入頻繁引發分裂;UUID v7(時序遞增)接近有序插入,分裂頻率大幅降低。高寫入量系統值得評估主鍵格式。

Polyglot Persistence 已是現代架構常態

「SQL 還是 NoSQL」在 2026 年的答案幾乎都是「兩者都用」。PostgreSQL 處理核心交易資料、Redis 快取、Elasticsearch 搜尋——多資料庫混用已是大型系統的標配。初期系統以 PostgreSQL 作為主庫是最安全的起點,再依實際瓶頸補位 NoSQL,避免過早引入架構複雜度。

反向連結

以下頁面引用了本頁: