【系統設計 20 概念】#04 資料庫核心 — SQL、ACID、NoSQL

測驗:資料庫核心 — SQL、ACID、NoSQL

共 5 題,點選答案後會立即顯示結果

1. SQL 資料庫中的 Schema(結構描述)指的是什麼?

  • A. 資料庫裡每一筆資料的唯一編號
  • B. 定義每個表格有哪些欄位與資料類型,而且是固定的
  • C. 一種用來加速查詢的索引機制
  • D. 把多張表格合在一起查詢的操作

2. ACID 中的 Atomicity(原子性)代表什麼意思?

情境:Alice 要轉 1000 元給 Bob,需要「Alice 帳戶 -1000」和「Bob 帳戶 +1000」兩步操作。

  • A. 資料庫設定的規則不會被任何操作打破
  • B. 資料寫入後即使斷電也不會遺失
  • C. 這兩步操作要嘛全部完成,要嘛全部不算,不會只做一半
  • D. 同時進行的多筆交易不會互相干擾

3. 以下哪個是 NoSQL「Key-Value」類型資料庫的代表,常用於快取和 Session 管理?

  • A. MongoDB
  • B. Cassandra
  • C. Neo4j
  • D. Redis

4. 下面這段代碼利用了 ACID 的哪個特性?

with session.begin(): alice.balance -= 1000 bob.balance += 1000 # 離開 with 區塊 → 自動 COMMIT # 如果中間出錯 → 自動 ROLLBACK
  • A. Atomicity(原子性)— 把多個操作包成一組,全做或全不做
  • B. Consistency(一致性)— 確保餘額不為負數
  • C. Isolation(隔離性)— 確保交易之間互不干擾
  • D. Durability(持久性)— 確保資料寫入後不會遺失

5. 如果你要建一個金融交易系統,需要精確的資料一致性和複雜的關聯查詢,最適合選擇哪種資料庫?

  • A. MongoDB — 因為 Schema 彈性,開發快速
  • B. PostgreSQL — 因為支援 ACID 和強大的 JOIN 查詢
  • C. Redis — 因為速度極快,延遲最低
  • D. Cassandra — 因為水平擴展能力強

本篇是「系統設計 20 概念」系列第 4 篇,共 5 篇。
前置知識:第 3 篇的擴展概念(理解為什麼需要不同資料庫)
參考來源:20 System Design Concepts Explained in 10 Minutes (NeetCode, YouTube)

一句話說明

資料庫就是「存放資料的倉庫」,SQL 和 NoSQL 是兩種不同的管理風格 — 一個像 Excel 表格,一個像 JSON 檔案。


為什麼 Vibe Coder 需要懂資料庫?

你請 AI 幫你寫後端程式時,它一定會幫你挑一個資料庫。你可能會看到:

# AI 可能寫出這樣的代碼
from sqlalchemy import create_engine
engine = create_engine("postgresql://localhost/myapp")
Code language: PHP (php)

或是:

// 或者這樣
const client = new MongoClient("mongodb://localhost:27017");
Code language: JavaScript (javascript)

一個用 PostgreSQL(SQL 資料庫),一個用 MongoDB(NoSQL 資料庫)。為什麼選這個不選那個?讀完本篇你就能看懂。


SQL 資料庫:像 Excel 一樣的表格

核心概念

SQL(Structured Query Language)資料庫把資料存在表格裡,跟 Excel 非常像:

users 表格:
+----+--------+-------------------+
| id | name   | email             |
+----+--------+-------------------+
| 1  | Alice  | alice@example.com |
| 2  | Bob    | bob@example.com   |
+----+--------+-------------------+

orders 表格:
+----+---------+---------+--------+
| id | user_id | product | amount |
+----+---------+---------+--------+
| 1  | 1       | 鍵盤    | 2500   |
| 2  | 1       | 滑鼠    | 800    |
| 3  | 2       | 螢幕    | 12000  |
+----+---------+---------+--------+

重點翻譯

  • Schema(結構描述):定義每個表格有哪些欄位、什麼類型。像 Excel 的表頭,而且是固定的 — 你不能突然在某一列多塞一個欄位。
  • Row(列):一筆資料。
  • Column(欄):一個欄位。
  • Primary Key(主鍵):每筆資料的身分證號碼,不能重複。上面的 id 就是主鍵。

JOIN:把兩張表格合在一起查

SQL 最強的能力就是 JOIN — 把有關聯的表格「接起來」查:

-- 查 Alice 的所有訂單
SELECT users.name, orders.product, orders.amount
FROM users
JOIN orders ON users.id = orders.user_id
WHERE users.name = 'Alice';
Code language: JavaScript (javascript)

白話翻譯

「從 users 表格和 orders 表格中,
 把 users.idorders.user_id 相同的列合在一起,
 只拿 Alice 的資料,
 顯示名字、商品、金額。」
Code language: CSS (css)

結果:

+-------+---------+--------+
| name  | product | amount |
+-------+---------+--------+
| Alice | 鍵盤    | 2500   |
| Alice | 滑鼠    | 800    |
+-------+---------+--------+

常見的 SQL 資料庫

資料庫 誰在用 一句話特色
PostgreSQL Instagram、Supabase 功能最完整,社群活躍
MySQL Facebook、Twitter 老牌穩定,速度快
SQLite 手機 App、小專案 不需要伺服器,一個檔案搞定

**Vibe Coder 提示**:如果你請 AI 做一個「有使用者登入、有訂單、資料之間有關聯」的應用程式,AI 大概率會選 PostgreSQL 或 MySQL。


ACID:資料庫的四大安全保證

ACID 是 SQL 資料庫最重要的特性。我們用銀行轉帳來理解:

情境:Alice 要轉 1000 元給 Bob。

這個動作需要兩步:

  1. Alice 帳戶 -1000
  2. Bob 帳戶 +1000

如果做完第一步、還沒做第二步就斷電了呢?Alice 少了 1000 元,Bob 卻沒收到。錢就這樣消失了。

ACID 就是為了防止這種事情而存在的:

A – Atomicity(原子性):全做或全不做

交易開始
  Alice 帳戶 -1000   ← 成功
  Bob 帳戶 +1000     ← 失敗(斷電了)
交易回滾 → Alice 帳戶恢復原狀

白話翻譯:「這組操作要嘛全部完成,要嘛全部不算。不會出現做一半的情況。」

就像你在超商買東西 — 付錢跟拿到商品是綁在一起的,不會只付了錢卻沒拿到東西。

C – Consistency(一致性):規則永遠不被打破

規則:帳戶餘額不能是負數

Alice 餘額:500
Alice 要轉 1000 給 Bob → 拒絕!因為 500 - 1000 = -500,違反規則

白話翻譯:「資料庫設定的規則,任何操作都不能打破。」

I – Isolation(隔離性):交易互不干擾

同一時間:
  交易 A:Alice 轉 1000 給 Bob
  交易 B:Alice 轉 500 給 Charlie

如果沒有隔離性:
  Alice 餘額 3000
  交易 A 讀到 3000,減 1000 = 2000
  交易 B 也讀到 3000,減 500 = 2500
  最後餘額 2500(應該是 1500!交易 A 的扣款被覆蓋了)

有隔離性:
  交易排隊執行,結果一定是 3000 - 1000 - 500 = 1500 ✓

白話翻譯:「同時進行的多個操作,結果跟一個一個排隊做是一樣的。」

D – Durability(持久性):寫入就不會遺失

交易完成 → 資料已寫入硬碟
即使下一秒伺服器爆炸 → 資料還在

白話翻譯:「資料庫說『存好了』,就是真的存好了,斷電也不會丟。」

ACID 速查表

特性 一句話 防止什麼問題
Atomicity 全做或全不做 操作做一半就壞掉
Consistency 規則不被打破 資料出現不合理的狀態
Isolation 交易互不干擾 同時操作導致數據錯亂
Durability 寫入就不丟 斷電後資料消失

**Vibe Coder 提示**:當你在代碼裡看到 BEGIN TRANSACTIONCOMMIT(或 ORM 的 session.begin()),就是在用 ACID 的原子性 — 把多個操作包成「一組」。

# AI 可能這樣寫(SQLAlchemy ORM)
with session.begin():          # 開始交易
    alice.balance -= 1000      # Alice 扣錢
    bob.balance += 1000        # Bob 加錢
# 離開 with 區塊 → 自動 COMMIT(全部完成)
# 如果中間出錯 → 自動 ROLLBACK(全部還原)
Code language: PHP (php)

NoSQL 資料庫:不用表格的彈性倉庫

為什麼需要 NoSQL?

SQL 資料庫很棒,但有些情況不太適合:

情境 SQL 的困難 NoSQL 的優勢
每個使用者的資料欄位不同 Schema 固定,改表格很痛苦 Schema 彈性,想加什麼加什麼
每秒百萬筆讀寫 垂直擴展有上限 水平擴展容易(多加機器就好)
資料是巢狀結構(JSON) 要拆成很多表格再 JOIN 直接存整個 JSON

NoSQL 的核心概念

NoSQL 的資料長這樣(以 Document 型為例):

{
  "_id": "user_001",
  "name": "Alice",
  "email": "alice@example.com",
  "orders": [
    { "product": "鍵盤", "amount": 2500 },
    { "product": "滑鼠", "amount": 800 }
  ],
  "preferences": {
    "theme": "dark",
    "language": "zh-TW"
  }
}
Code language: JSON / JSON with Comments (json)

跟 SQL 的關鍵差異

  • 不需要事先定義欄位(沒有固定 Schema)
  • 資料可以是巢狀的(orders 直接放在 user 裡面)
  • 不同筆資料可以有不同的欄位

四種 NoSQL 類型

1. Key-Value(鍵值對)– 最簡單

"session_abc123" → { user_id: 1, login_time: "..." }
"cache_homepage" → "<html>..."
Code language: CSS (css)

白話翻譯:「就像一個超大的字典/HashMap。給一個 key,拿到一個 value。」

代表 常見用途
Redis 快取、Session、排行榜
Memcached 純快取

速度極快(資料存在記憶體),但查詢能力有限 — 只能用 key 去找。

2. Document(文件型)– 最常見

// MongoDB 裡的一筆資料
{
  "_id": ObjectId("..."),
  "title": "系統設計入門",
  "author": { "name": "Alice", "bio": "..." },
  "tags": ["system-design", "backend"],
  "comments": [
    { "user": "Bob", "text": "好文!" }
  ]
}
Code language: JSON / JSON with Comments (json)

白話翻譯:「每筆資料就是一個 JSON 文件。結構可以隨便改,查詢功能也不錯。」

代表 誰在用
MongoDB 很多新創公司的預設選擇
DynamoDB AWS 上最常用的 NoSQL

3. Column-Family(欄族型)– 大數據專用

Row Key: "user_001"
  Column Family "profile": { name: "Alice", email: "..." }
  Column Family "activity": { last_login: "...", page_views: 50000 }
Code language: CSS (css)

白話翻譯:「把相關的欄位分組存放,擅長處理海量資料的讀寫。」

代表 誰在用
Cassandra Netflix、Discord(處理每天數十億筆事件)
HBase 大數據分析

4. Graph(圖型)– 關係網絡專用

(Alice) --[追蹤]--> (Bob)
(Bob)   --[追蹤]--> (Charlie)
(Alice) --[追蹤]--> (Charlie)

查詢:「Alice 的朋友的朋友是誰?」→ 一步搞定
(SQL 要寫多層 JOIN,很慢)
Code language: CSS (css)

白話翻譯:「專門處理『誰跟誰有關係』的資料。社群網路、推薦系統最愛用。」

代表 誰在用
Neo4j 社群網路、知識圖譜
Amazon Neptune AWS 上的圖資料庫

SQL vs NoSQL:完整對比

比較項目 SQL NoSQL
資料結構 固定表格(Schema) 彈性(Schema-less)
關聯查詢 JOIN 很強 通常不支援 JOIN
擴展方式 垂直擴展(升級單台機器) 水平擴展(加更多機器)
一致性 強一致性(ACID) 最終一致性(可能有短暫延遲)
適合場景 金融、電商、需要精確數據 社群、IoT、大量讀寫
代表產品 PostgreSQL、MySQL MongoDB、Redis、Cassandra

什麼時候選 SQL?

  • 資料之間有明確的關聯(使用者 – 訂單 – 商品)
  • 需要複雜的查詢(多張表格 JOIN)
  • 資料正確性非常重要(金融交易、庫存管理)
  • 資料結構穩定,不常改變

什麼時候選 NoSQL?

  • 資料結構經常變動(每個使用者有不同欄位)
  • 需要處理大量讀寫(每秒數萬到數百萬筆)
  • 資料是巢狀結構(JSON/文件型)
  • 可以接受短暫的資料不一致

真實世界的選擇

公司 選擇 原因
Instagram PostgreSQL 使用者、貼文、留言之間有大量關聯
Netflix Cassandra 全球數億用戶的觀看記錄,需要超大規模寫入
Uber 混合使用 PostgreSQL 存核心交易,Redis 做即時定位快取
Discord Cassandra → ScyllaDB 每天數十億筆訊息,需要極高寫入效能

**重要觀念**:SQL vs NoSQL 不是「誰比較好」,而是「什麼場景用什麼工具」。大多數現代系統會**混合使用** — 核心資料用 SQL,快取和日誌用 NoSQL。


Vibe Coder 檢查點

當你請 AI 幫你建專案,看到資料庫相關的代碼時,確認以下幾點:

  • [ ] AI 選了哪種資料庫? 看 connection string(postgresql:// vs mongodb:// vs redis://
  • [ ] 有沒有 Schema/Model 定義? SQL 類一定有(像 CREATE TABLE 或 ORM 的 class),NoSQL 可能沒有
  • [ ] 有沒有用 Transaction? 涉及多步操作(轉帳、下單)時,應該要看到 BEGIN/COMMITsession.begin()
  • [ ] 資料之間的關聯怎麼處理? SQL 用 JOIN,NoSQL 通常把相關資料塞在同一個文件裡

必看懂 vs 知道就好

必看懂(AI 生成的代碼一定會出現):
  - CREATE TABLE / Model 定義
  - SELECT ... FROM ... WHERE
  - JOIN(把表格合在一起查)
  - INSERT / UPDATE / DELETE
  - Transaction(BEGIN / COMMIT / ROLLBACK)

知道就好(遇到再查):
  - INDEX(加快查詢的索引)
  - VIEW(虛擬表格)
  - Stored Procedure(存在資料庫裡的程式)
  - Sharding(把資料分散到多台機器)
  - Replication(資料複製到多台機器做備份)

本篇重點回顧

  1. SQL 資料庫:資料存在固定結構的表格裡,靠 JOIN 連接不同表格,適合有明確關聯的資料。
  2. ACID:SQL 資料庫的四大安全保證 — 原子性(全做或全不做)、一致性(規則不被打破)、隔離性(交易互不干擾)、持久性(寫入就不丟)。
  3. NoSQL 資料庫:結構彈性、容易水平擴展,但通常犧牲部分一致性。四種類型各有專長:Key-Value(快取)、Document(通用)、Column-Family(大數據)、Graph(關係網絡)。
  4. 選擇原則:不是「哪個比較好」,而是「什麼場景用什麼」。現代系統通常混合使用。

下一篇我們會進入 API 與通訊機制,看看系統之間是怎麼「對話」的。

進階測驗:資料庫核心 — SQL、ACID、NoSQL

測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。

1. 你正在開發一個即時聊天應用,預計每天會產生數十億筆訊息。訊息格式簡單(發送者、接收者、內容、時間戳),但寫入量極大。你應該選擇哪種資料庫? 情境題

  • A. PostgreSQL — 因為支援 ACID,能確保每筆訊息不會遺失
  • B. MongoDB — 因為 Schema 彈性,可以隨時調整訊息格式
  • C. Cassandra — 因為擅長處理海量寫入,且水平擴展容易
  • D. Redis — 因為速度極快,資料存在記憶體中

2. 你的電商平台需要同時處理以下需求:使用者下單時要確保庫存扣減和金額扣款同時成功或同時失敗,同時首頁商品推薦需要毫秒級回應。最合理的架構是什麼? 情境題

  • A. 全部使用 PostgreSQL,因為 ACID 保證資料正確
  • B. 全部使用 MongoDB,因為查詢速度快又彈性
  • C. 全部使用 Redis,因為毫秒級回應最重要
  • D. 混合使用:PostgreSQL 處理訂單交易(需要 ACID),Redis 做商品推薦快取

3. 你正在建一個社群平台的「好友推薦」功能,需要查詢「我的朋友的朋友中,哪些人我還沒追蹤」。哪種 NoSQL 類型最適合這個場景? 情境題

  • A. Document(文件型)– 把每個使用者的好友列表存成 JSON 陣列
  • B. Graph(圖型)– 專門處理「誰跟誰有關係」的多層查詢
  • C. Key-Value(鍵值對)– 用使用者 ID 當 key,快速查找
  • D. Column-Family(欄族型)– 把使用者資料分組存放

4. 小明寫了以下轉帳代碼,但測試時發現有時候錢會「憑空消失」。問題出在哪? 錯誤診斷

# 小明的轉帳代碼 def transfer(from_user, to_user, amount): from_user.balance -= amount # 第 1 步:扣款 db.save(from_user) # 寫入資料庫 to_user.balance += amount # 第 2 步:加款 db.save(to_user) # 寫入資料庫
  • A. 應該先檢查 from_user.balance 是否足夠,缺少一致性檢查
  • B. 沒有使用 Transaction,如果第 1 步成功但第 2 步失敗,扣款不會被回滾
  • C. 應該用 NoSQL 資料庫取代 SQL,才能處理高併發
  • D. db.save() 不是正確的寫入方法,應該用 db.commit()

5. AI 幫小美產生了以下代碼來存使用者的個人設定。每個使用者的設定欄位都不同(有人設了主題色、有人設了語言偏好、有人什麼都沒設)。小美用了 SQL 資料庫,但遇到了問題。最可能的問題是什麼? 錯誤診斷

CREATE TABLE user_preferences ( user_id INT PRIMARY KEY, theme VARCHAR(50), language VARCHAR(10), font_size INT, sidebar BOOLEAN, — 每次有新設定項就要加一個欄位… );
  • A. VARCHAR 類型不適合存設定值,應該用 TEXT 類型
  • B. 沒有設定 INDEX,查詢速度會很慢
  • C. SQL 的 Schema 是固定的,每次新增設定項都需要改表格結構,應該考慮用 NoSQL(如 MongoDB)直接存 JSON
  • D. 缺少 ACID Transaction,多個設定同時更新會互相覆蓋

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *