核心概念
設計資料庫的本質是「把現實世界的事物,翻譯成電腦能夠儲存與查詢的結構」。在動手建表之前,有八個底層邏輯必須先搞清楚。
一、資料建模(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)
索引讓資料庫不必掃描全表就能定位資料,類似書本的目錄。常在 WHERE、JOIN、ORDER 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:N 訂單、訂單 N:N 商品(透過訂單明細)
- 每個實體加主鍵
id,關聯用外鍵連接 - 在
orders.user_id、order_items.order_id、order_items.product_id加索引 - 結帳流程(扣庫存 + 建訂單)放進同一個 transaction
這五步走完,schema 的邏輯正確性就有基本保障。
延伸觀點
正規化不是終點,反正規化是刻意決策
正規化與反正規化並非對立,而是針對不同工作負載的工具。10K 用戶下有效的 schema,在千萬用戶時可能成為瓶頸。OLTP 系統(高頻交易)傾向正規化保障一致性,分析型系統(讀多寫少)則常反正規化減少 JOIN 成本。實務原則:先正規化設計,再根據真實效能數據決定哪裡值得反正規化,不要未量測就預先優化。
索引的隱藏成本:B-tree 頁面分裂
索引的寫入開銷不只是「更新索引樹」。B-tree 索引以固定大小的頁面儲存資料,頁面寫滿後插入新資料會觸發「頁面分裂」,產生額外磁碟操作與碎片化。一個常被忽略的細節:UUID v4(隨機)作為主鍵,隨機插入頻繁引發分裂;UUID v7(時序遞增)接近有序插入,分裂頻率大幅降低。高寫入量系統值得評估主鍵格式。
Polyglot Persistence 已是現代架構常態
「SQL 還是 NoSQL」在 2026 年的答案幾乎都是「兩者都用」。PostgreSQL 處理核心交易資料、Redis 快取、Elasticsearch 搜尋——多資料庫混用已是大型系統的標配。初期系統以 PostgreSQL 作為主庫是最安全的起點,再依實際瓶頸補位 NoSQL,避免過早引入架構複雜度。
反向連結
以下頁面引用了本頁: