MODULE 6 · 資料庫 · 6-5

市面上資料庫百百種,
你的 App 該選哪個?

資料庫是 App 最早、也最難改的決定。先看選錯多痛,再把 SQL 和 NoSQL 一次搞懂,學會跟 AI 一起替你的 App 選對。

§1 · 為什麼選對重要

選錯資料庫,半年後才會痛

資料庫是 App 最早、也最難改的決定。選的當下都沒事,但流量長大後,當初的選擇會一個一個變成帳單與災難。拖時間軸看看。

技術債Demo 能跑 ≠ 選對了
爆掉不是「突然」,是前期選擇埋下的債,流量長大才一次討回來。拖下面這條軸,看每階段冒出的麻煩。
📅 產品時間軸,拖滑桿看每個階段
Demo第 1 週100 用戶第 1 個月10k 用戶第 6 個月1M 用戶第 1 ~ 2 年
Demo< 10 用戶第 1 週
你 + 朋友幾個人試玩
暫時沒事,但前期的選擇正在累積
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 給的方案只解「現在能不能跑」,半年後爆的事不在它的視野裡。Demo OK 不等於可上線、可上線不等於撐得起規模。
💬怎麼跟 AI 講
規劃時固定問兩題:「半年後流量長 10 倍還跑得動嗎?瓶頸會在哪?」「如果之後想換一個資料庫,要付出多大代價?」逼 AI 一起看長期。

→ 既然選對這麼重要,下一步先認識:市面上到底有哪些主流的資料庫,它們差在哪。

§2 · 主流資料庫總覽

市面上資料庫百百種,先分成兩大派

先認得幾個主流資料庫,再看最大的分水嶺:SQL 還是 NoSQL。

📇 SQL 派 · 關聯式SQL
PostgreSQL關聯式
MySQL關聯式
SQLite關聯式 · 內嵌輕量
📇 NoSQL 派 · 文件 / KVNoSQL
MongoDB文件式
Firestore文件式 · 即時同步
DynamoDB鍵值 / 文件

最大的分水嶺只有一個:SQL 還是 NoSQL,背後是兩套設計哲學。

SQL關聯式哲學
切成多張 、用 id 互指、有強保證(ACID)。為「正確性 > 彈性」設計。
NoSQL非關聯式哲學
「會一起讀」的資料整坨包成一份 JSON document、結構自由、讀超快。為「彈性 > 強保證」設計。
🆚 想一眼看 SQL vs NoSQL 全對照?(展開 6 個維度)
結構
SQL
多表 + 外鍵互指
NoSQL
整坨 document(JSON)一包
查詢
SQL
JOIN 把多表拼回來
NoSQL
一個請求拿到完整資料
一致性
SQL
強保證(ACID)
NoSQL
為速度妥協(最終一致)
擴展
SQL
垂直加 CPU + 主從複製
NoSQL
水平加機器更原生
代表產品
SQL
PostgreSQL / MySQL / SQLite
NoSQL
Firestore / MongoDB / DynamoDB
適合場景
SQL
轉帳、訂單、複雜關聯
NoSQL
IG feed、聊天、巨量讀取

→ 先把 SQL 一次講完(關聯式、JOIN、ACID),再把 NoSQL 一次講完(Document Model、CAP),最後比較取捨。

🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 沒 context 時,預設常常直接推 Firebase,但它不知道你要哪個陣營,結果常常是「能跑、但不適合」。
💬怎麼跟 AI 講
直接報出三件事:結構(固定 / 常變)、一致性(絕不能錯 / 容許暫時不一致)、查詢模式(多表關聯 / 整坨讀完),AI 才能挑對陣營。

→ 先進入 SQL 這一派,下一段看關聯式資料庫到底怎麼工作。

§3 · 關聯式模型

SQL 的世界:一堆表,用 id 互相指

上一段給了兩派高層比較,這段進入 SQL 這一派背後的設計:關聯式模型(1970 年 Codd 提出)。

SQL 的底層哲學「關聯式模型」:把資料切成多張 ,每張只描述一種東西,表跟表之間用 id 互相指。

PKPrimary Key(主鍵)
每筆資料的「身分證號」,例如 users.id。不能重複、不能空。
FKForeign Key(外鍵)
orders.user_id 指向 users.id;DB 會檢查被指的對象一定要存在。
users2 rows
idnameemail
u1小明a@x.com
u2小華b@x.com
orders3 rows
iduser_idproduct_idqty
o1u1p12
o2u2p11
o3u1p23
products2 rows
idnameprice
p1拿鐵120
p2可頌80
👆 滑鼠移到中間 orders 任一列,看 FK 箭頭
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 為了「demo 快」可能把多種實體混塞同一張表,看起來能跑,但少了 FK 約束,髒資料一進來就找不到罪魁禍首。
💬怎麼跟 AI 講
檢查 AI 給的 schema:「每個實體是不是有獨立的表?」「有沒有 FOREIGN KEY 約束讓 DB 幫你守門?」,沒有就要求補上。

補:Normalization vs Denormalization,重複資料是萬惡之源

正規化Normalization
把重複資料拆出來、只存 id 連回去。改名字只動一個地方,代價是讀取要 JOIN 拼回來。
反正規化Denormalization
為了讀快、故意重複存。是有意識的取捨,不是疏忽。

按下面兩顆按鈕體感差別:同樣「把小明改名」,扁平表要動 3 筆,正規化只動 1 筆。

DENORMALIZED全塞一張表
orderauthoremailproduct
o1小明ming@x.com拿鐵
o2小華hua@x.com拿鐵
o3小明ming@x.com可頌
o4小明ming@x.com拿鐵
NORMALIZED拆 users / orders / products
users
u1小明ming@x.com
u2小華hua@x.com
orders 的 author 只存 user_id → 自動看到新名字
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 預設給扁平 schema(一張表全包),因為「直覺好懂、寫起來快」。但 同一個欄位被多筆共用時,改一次資料要批次更新整張表,bug 等著你。
💬怎麼跟 AI 講
每看到一個欄位都問:「這個欄位之後會被多筆 row 共用嗎?」會 → 要求 AI 拆成獨立的表,用 FK 連回去。讀的時候再用 JOIN 拼回來。

→ 切表之後,要用時得想辦法把表拼回來,這就是下一段的 JOIN。

§4 · JOIN

JOIN,把多張表拼起來

前面把資料切成多張表,這段把表拼回來。切換 4 種 JOIN 看「誰留下、誰被丟掉」。

把切開的表 拼回來 叫 JOIN。四種寫法差別只在一件事:對不上的列要不要留?下面故意放兩個邊界 case(沒下單的小美、用戶已刪的舊訂單),切換 4 種 JOIN 看誰留誰丟。

usersordersINNER JOIN
INNER JOIN只要「兩邊都對得上」的,對不上的整列丟掉
結果表留下 3 / 5 列
useritem這列的命運
小明拿鐵✓ 配對成功,留下
小華可頌✓ 配對成功,留下
小明美式✓ 配對成功,留下
小美NULL✗ 丟掉(users 有,沒下過訂單
NULL舊訂單(用戶已刪)✗ 丟掉(orders 有,用戶被刪了
實際 SQL 長這樣(AI 會給你這種 code)
SELECT users.name, orders.item
FROM   users
INNER JOIN orders
  ON   users.id = orders.user_id
⚠️ 選這個會漏掉什麼:小美(沒下單)+ 舊訂單(用戶已刪)都被默默丟掉。做「月活用戶」或「總營收對帳」會少算,而且看不到任何錯誤訊息。
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 給的 NoSQL 方案常寫「先抓 users、再 for-loop 依 user_id 抓 orders」,這叫 N+1 query,1000 個用戶就打 1001 次資料庫,效能爆炸。
💬怎麼跟 AI 講
看到迴圈裡有查詢,問:「這段是不是 N+1?能不能用 JOIN 合成一句、或用 batch query 預載?」,把 query 數量明確列出來,AI 才會優化。

→ JOIN 把資料拼回來,但 SQL 真正的看家本領是「保證不出錯」,這就是下一段的 ACID。

§5 · ACID + Transaction

銀行轉帳:少了哪個字母會出什麼事?

JOIN 讓你查得到資料,但 SQL 最厲害的其實是「保證不出錯」,這就是 ACID。按按鈕看四種「壞掉的轉帳」,每種對應 ACID 少了一個字母。

轉帳要做兩件事(A -$100、B +$100),中間不管出什麼狀況錢都不能憑空消失。這四個保證合起來叫 ACID,打包在一起叫 Transaction。按下面五顆按鈕,看少了哪個字母會出什麼事。

AAtomicity 原子性
要嘛全成、要嘛全廢,不會只做一半。
CConsistency 一致性
內建規矩(餘額不能變負)永遠不破。
IIsolation 隔離性
兩人同時操作,結果跟輪流做一樣。
DDurability 持久性
說成功就算數,下一秒停電也不反悔。
🏦 vibe-bank.com / 轉帳系統
ATM-A
vibe-bank
ACCOUNT A
$1,000
● ready
$100
轉帳
ATM-B
vibe-bank
ACCOUNT B
$1,000
● ready
合計:$2000(應該永遠是 $2000)
// 點按鈕看 transaction log
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 寫多步驟操作(轉帳、扣庫存+建訂單、刪用戶+清關聯)預設不會自己包 transaction。Demo 時看不出,真實流量裡中間 crash 一次,資料就壞了。
💬怎麼跟 AI 講
看到「要嘛同生、要嘛同死」的場景,直接問:「這段要包在 transaction 裡嗎?BEGIN / COMMIT 怎麼放?失敗 rollback 怎麼處理?

→ 關聯式、JOIN、ACID,SQL 這一派到這裡講完了。接下來換另一派 NoSQL,先看它的核心 Document Model。

§6 · 非關聯式 / Document Model

NoSQL 的世界:整坨資料用 JSON 裝在一起

跟 SQL 對立的哲學:不切表,整坨包成 document。同樣是作者改名,NoSQL 要動 12 筆、SQL 只動 1 筆。

NoSQL 文件式(Firestore、MongoDB)跟 SQL 相反:不切表,把「會一起讀」的資料整坨包成一份 JSON document。

優點讀取超快、結構自由
整筆一次取出、不用 JOIN;新欄位直接寫,不用 ALTER TABLE。
代價資料重複存
每篇 post 都存著作者名字,作者改名要批次更新所有 post。下面點兩顆按鈕體感差別。
posts (firestore)12 docs
{ id: "post_1", author: { name: "小明" } }
{ id: "post_2", author: { name: "小明" } }
{ id: "post_3", author: { name: "小明" } }
{ id: "post_4", author: { name: "小明" } }
{ id: "post_5", author: { name: "小明" } }
{ id: "post_6", author: { name: "小明" } }
{ id: "post_7", author: { name: "小明" } }
{ id: "post_8", author: { name: "小明" } }
{ id: "post_9", author: { name: "小明" } }
{ id: "post_10", author: { name: "小明" } }
{ id: "post_11", author: { name: "小明" } }
{ id: "post_12", author: { name: "小明" } }
未開始0/12
psql,users + posts JOIN1 user · 12 posts
// users 表(只存一份名字)
u1 小明 | ming@x.com
// posts 表(每筆只存 user_id 引用)
post_1 · user_id=u1
post_2 · user_id=u1
post_3 · user_id=u1
post_4 · user_id=u1
... 共 12 筆 posts
// JOIN 時自動拿到新 name,不用動 posts
未開始0/1
📊 寫入次數比:NoSQL 0 vs SQL 0
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 給的 NoSQL schema 為了「讀取方便」常把作者、商品等共用資料 內嵌在每筆 document。看起來巧妙,但被嵌的資料一改 → 要批次更新所有 document,做不到就資料不一致。
💬怎麼跟 AI 講
看到內嵌的子物件,問:「這份資料之後會被多筆 document 共用嗎?會被多人改嗎?」會 → 抽出來做引用(存 id),不要直接內嵌。

分散式 NoSQL 的另一個取捨,CAP 三選二

資料一旦 分散到多台,就撞上分散式系統的鐵則 CAP 定理:下面三個 最多同時有兩個。P 是現實(網路本來就會斷),所以真正的選擇是 CP 還是 AP。拖三角看取捨。

CConsistency 一致性
所有節點同一刻看到同一份資料。
AAvailability 可用性
每個請求都有回應,不 timeout、不拒絕。
PPartition 分割容忍
節點間網路斷掉時,系統還能跑。
🔺 CAP 三角,拖點看取捨
CConsistencyAAvailabilityPPartition Tolerance✗ 放棄
當前選擇
CA
你保留的
Consistency + Availability
你放棄的
Partition Tolerance
代表產品:單機資料庫(PostgreSQL 在一台機器上)
什麼情境:只要不分散就有 C + A,但分散式系統「網路分割」不可避免,所以 CA 在分散式情境其實做不到。
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 推「分散式 DB」時,常只說「擴展性好」,不會主動講 CAP 取捨,網路分割時你的系統會選 C 還是 A?這直接影響用戶體驗。
💬怎麼跟 AI 講
聽到「分散式」、「多 region」、「跨機房」這些詞,主動問:「這套系統是 CP 還是 AP?網路分割時會犧牲什麼?我的場景能接受嗎?

→ SQL 跟 NoSQL 兩派都看完了,接下來把它們放一起比較:改結構時,各自要付出什麼代價。

§7 · 結構彈性的取捨

加一個欄位,SQL 5 步驟、NoSQL 直接寫

SQL 嚴格 schema 跟 NoSQL 彈性 schema 改起來代價差很多。產品快速迭代時加欄位是日常,方便有代價,只是「方便」被推到哪去而已。

產品長大常要「加新欄位」。「方便」不會消失,只是被推到不同地方。下面兩顆按鈕體感差別。

SQL嚴格 schema
要先 ALTER TABLE 宣告、回填舊資料。大表可能 鎖表幾分鐘到幾小時
NoSQL彈性 schema
直接寫新欄位就好,但代價 推給應用層:每讀一筆都要 ?? "default"
SQL · 5 步驟
加 ar_filter 欄位
NoSQL · 直接寫
加 ar_filter 欄位
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 給的 migration 直接 ALTER TABLE 不提鎖表時間。小表沒事,但 100 萬筆以上的大表 ALTER 可能鎖數分鐘到數小時,整個 App 寫不進去。
💬怎麼跟 AI 講
看到 migration 主動問:「這張表多大?ALTER 預估鎖多久?要不要排上線時段或用 online migration 工具?」,把規模講出來 AI 才會給對的策略。

→ 概念都齊了,接下來先看 AI 時代最常見的後端長什麼樣。

§8 · AI App 後端

想做一個 ChatGPT 類產品?這是資料庫該有的樣子

一個 vibe coder 的開發直播:每加一個需求,自然逼出一張表。點按鈕,跟著長一遍。

📈需求演進,每加一個需求,下面畫面對應的位置就會亮0/4
空白的產品,還沒有任何表。點下面按鈕,從第一個需求開始長出你的後端。
畫面 → 後端對照圖
先加需求,這裡會一個個亮起
2Chats
Schema 設計
向量搜尋
Vibe coding
GPT-4
542/100
1
pgvector 跟 Pinecone 怎麼選?
小規模用 pgvector 一張表搞定,相似度搜尋用 cosine...
3messages·4向量檢索
6📎
Message ChatGPT...
儲存色系:SQLVector DBRedisS3
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 預設給你「一張 messages 表吃全部」,簡單,但加上 RAG、rate limit、付費方案那一刻全爆。或者它直接推 Pinecone + Firebase + R2 一整套,小規模太重、帳單炸鍋。
💬怎麼跟 AI 講
講需求分階段:先講「MVP 最小架構」,再講「規模化後拆什麼」。也可以主動帶這四題把 AI 釘到位:➀ 對話跟訊息要分開兩張表,對嗎?➁ embeddings 第一天就用 pgvector,還是先用 jsonb 欄位?➂ rate limit 走 Redis 還是 PostgreSQL?➃ 檔案放 S3、DB 只存 metadata,對嗎?

→ 概念跟範本都看過了,換你做選擇練習:下一段用 5 個場景測測你的直覺。

§9 · 怎麼判斷該用哪個 + 實戰

5 題場景速測:你會直覺選哪一邊?

前面把概念都講完了,這段把它們套到 5 個具體場景。從 SQL / NoSQL / Key-Value 三個選項挑一個,立即知道對錯 + 為什麼。

選資料庫先看 場景特性,不是先看名字。下面 5 題每題給一個場景、3 個選項,先憑直覺答,答錯沒關係。

🏦Q1. 銀行轉帳
  • · 絕不能掉錢
  • · 兩個帳戶同步改
  • · 結構固定
📸Q2. Instagram 動態
  • · 每篇 post 結構不一
  • · 新欄位常加
  • · 巨量讀取
💬Q3. 聊天室即時訊息
  • · 訊息只增不改
  • · 需即時推送
  • · 搜尋頻率低
🛒Q4. 電商訂單系統
  • · 訂單 → 商品 → 用戶有複雜關聯
  • · 要對帳、要 JOIN
  • · 資料正確性 > 速度
🎮Q5. 多人遊戲 leaderboard
  • · 排名變動超頻繁
  • · 讀取量 >> 寫入量
  • · 結構超簡單
進度:0/5
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
選資料庫沒有「絕對的好」,只有「在這個場景比較適合」。AI 沒看清楚場景,預設給你最熱門的那個(多半是 Firebase)。
💬怎麼跟 AI 講
看到新需求先問自己三件事:「結構固定嗎?」「多筆要同時改嗎?」「絕不能掉嗎?」三個都 yes → 跟 AI 說 SQL;結構常變、巢狀深、單筆操作 → 跟 AI 說 NoSQL;速度第一、結構超簡單 → 跟 AI 說 KV。

每個陣營有哪些代表產品,5 題挑挑看

知道四個陣營後,下一層是「每個陣營有哪些代表產品」。不用背特性,看到名字能反應「它大概解什麼問題」就夠了。

進度 0 / 5 · 答對 0
Q1

你要做一個轉帳系統,需要 ACID 保證、強一致性。AI 應該推薦哪個?

💳 Bank App✓ Synced
*.4521 儲蓄
*.8763 王小明
金額NT$ 1,000
✅ 成功 #TX25038,420 → 7,420
Q2

你要做即時協作聊天 App,訊息要「資料變了 client 自動收到」。AI 預設會推哪個?

💬 設計組 #general● 5 在線
alex 收到~下午 3 點✓✓
mia +1 我準時
alex 正在輸入...
Q3

你要做一個 AI 客服 + RAG 語意搜尋,剛起步、規模小。AI 應該推哪個?

🤖 AI 客服
你:退貨流程要多久?
AI:收到貨後 7 個工作天會退款到原付款方式。
📎 來源:退貨政策 v3.2 · FAQ #18相似度 0.92 · 0.87
Q4

你要做 API 限流(每個 user 每分鐘最多 100 次),計數要超快。AI 推哪個?

⚡ /api/search1m window
user_4521▓▓▓▓▓▓▓▓░░87/100
user_9988▓▓▓▓▓▓▓▓▓▓100/100
user_3310▓▓░░░░░░░░18/100
⚠ user_9988 → 429 Too Many Requests
Q5

你是 vibe coder,想要一站式後端(資料庫 + 登入 + 即時同步 + Storage),不想自己架 server,資料結構也會邊做邊改。AI 推哪個?

🔥 Firebase Console
🔥 Firestore8 collections
👤 Authentication142
📦 orders1.2k
🔑 Sign-inGoogle ✓ GitHub ✓
my-app-1234.firebaseapp.com
🔑VIBE CODER 秘訣點一下看這題秘訣
👀觀察
AI 沒 context 預設直接推 Firebase,對 80% 的小專案剛好,但對你那 20% 特殊場景可能完全不對(高並發、向量搜尋、強一致需求)。
💬怎麼跟 AI 講
給 AI 推薦時把 5 件事描述清楚:流量規模、結構複雜度、是否需要 ACID、是否需要向量搜尋、團隊規模。然後說:「列 2~3 個選項並比較」,強迫權衡。

→ 走完整個單元,你已經有跟 AI 對話的全套後端直覺,最後一段把它收口。

§10 · 收尾

這個 Unit 你帶走了什麼

SQL vs NoSQL 不是「哪個比較好」,
是「在這個場景哪個比較適合」。

跟 AI 討論架構時可以直接用的 7 個直覺:

  • · 轉帳場景 → 想到 ACID、Transaction、SQL
  • · 資料有複雜關聯 → 想到 JOIN、想到關聯式
  • · 巢狀資料、結構常變 → 想到 Document Model、想到 NoSQL
  • · 看到「先抓再抓」 → 想到 JOIN,問能不能合成一句
  • · 看到「加欄位」 → 評估遷移代價,考慮 jsonb 欄位
  • · 分散式 DB → 想到 CAP,問放棄了什麼
  • · AI App 後端 → users / conversations / messages / embeddings / rate_limits / files 六件套
📍 接下來
Part 2 預告:資料模型設計,Schema 是 vibe coder 的劇本

知道選哪個陣營之後,下一步是學會「畫出你的 App 的資料地圖」,怎麼跟 AI 一起把 schema 設計好,少踩遷移地獄。