資料庫技術練習題 (Practice - Database Tech)
Related Concepts
- 06-Database-Tech/01-Database
- 06-Database-Tech/02-PostgreSQL
- 06-Database-Tech/03-DynamoDB
- 06-Database-Tech/04-OLTP-vs-OLAP
| 概念 | 預設做法 | 關鍵點 |
|---|---|---|
| 資料庫選型 | 從需求推導(形狀 → OLTP/OLAP → 規模/一致性) | 別背 SQL vs NoSQL 比較表 |
| 一般首選 | PostgreSQL(再說明為何偏離) | ACID + JSONB + GIN + PostGIS |
| PG 拍賣競態 | SELECT FOR UPDATE 列鎖 |
不要動不動上 Serializable |
| DynamoDB 主鍵 | Partition Key(hash)+ Sort Key(範圍) | 均勻分散 + 契合查詢 |
| GSI vs LSI | GSI 不同 PK/可隨時建/僅最終一致;LSI 同 PK/建表時定 | GSI ≤20、LSI ≤5 |
| OLTP vs OLAP | Row-oriented vs Column-oriented | column 快=I/O+壓縮+向量化 |
| 連接管線 | ETL(簡單)/ CDC(近即時)/ ELT(dbt) | 先 ETL,確認即時需求再 CDC |
Part 1:Database 總覽與選型
Q1(Recall):理解資料庫的兩個正交維度是什麼?
- 資料模型(Data Model):資料形狀 —— 表格 / 文件 / Key-Value / 寬欄 / 圖 / 向量
- 工作負載(Workload):OLTP(高並發點查詢、小量寫入)還是 OLAP(海量歷史聚合分析)
兩者互相獨立。疊在一起,大多數資料庫的定位就清楚了。
Q2(Recall):NoSQL 的五種資料模型各自的代表與擅長場景?
- Key-Value(Redis、DynamoDB):快取、Session、計數器、排行榜
- Document(MongoDB):CMS、產品目錄、schema 需靈活演進
- Wide-Column(Cassandra):高寫入吞吐、時序、明確 access pattern
- Graph(Neo4j):社交網路、推薦、知識圖譜(多跳查詢比多層 JOIN 快幾個數量級)
- Vector(Pinecone、pgvector):語意搜尋、RAG、以圖搜圖
共同取捨:多數遵循 BASE(最終一致)而非 ACID,換取水平擴展。
Q3(Recall):Cassandra 是 OLTP 還是 OLAP 系統?為什麼?
OLTP。Cassandra「write anywhere」用最終一致換超高寫入吞吐 + 無單點故障,但它按 row 儲存,適合高並發寫入與明確 primary key 查詢,不適合跨 row 的聚合分析。把它當分析系統是常見誤解。
Q4(Application):面試官問你選資料庫,你不該怎麼做?正確的思路是什麼?
不該一上來就背「SQL vs NoSQL」比較表 —— 面試官想看你從需求推導選擇的過程。
依序問三個問題:
- 資料什麼形狀、什麼查詢模式?(固定結構+JOIN → RDBMS;KV+低延遲 → DynamoDB/Redis;非結構化+相似度 → Vector DB…)
- OLTP 還是 OLAP?(分析需求 → 獨立資料倉儲)
- 規模與一致性取捨?(強一致+複雜查詢 → RDBMS;輕鬆水平擴展+可接受最終一致 → NoSQL)
選完一定說出理由(選 PG 強調 ACID/JOIN/生態;選 DynamoDB 強調低延遲/托管擴展)。
Q5(Application):什麼時候不需要複雜的資料庫?
- MVP / 小型系統 → SQLite 或單一 PostgreSQL
- 單純快取需求 → Redis / Memcached,不要上 MongoDB
- 單純檔案儲存(圖片、影片、大型文件)→ Blob Storage,不要塞進資料庫
重點是避免 over-engineering。
Part 2:PostgreSQL
Q6(Recall):PostgreSQL 的進階索引各解決什麼問題、各可能省掉哪個專用系統?
- GIN 索引(全文搜尋 / tsvector)→ 簡單搜尋不必上 Elasticsearch
- JSONB + GIN(靈活 metadata、半結構化)→ 給類 NoSQL 彈性,不必上 MongoDB
- PostGIS(GIST 索引)(地理空間)→ 不必上專用地理 DB(Uber 早期就用它)
但若需更精細的相關性評分、faceted search、超大規模分散式搜尋,才該真的引入 Elasticsearch。原則:架構越簡單越好。
Q7(Recall):PostgreSQL 一筆寫入的路徑是什麼?瓶頸通常在哪?
- 修改記憶體 buffer(標記髒頁)+ 產生 WAL 記錄(都在記憶體)
- commit 時 WAL 循序寫進磁碟(fsync)→ 交易即持久化(崩潰可重播 WAL 恢復)
- 背景寫入程序非同步把髒頁刷進資料檔(可批次)
- 每個索引更新(→ 太多索引大幅拖慢寫入)
瓶頸通常卡在 WAL 的磁碟 I/O。單節點中等硬體約 5,000 簡單 INSERT/核心/秒。
Q8(Application):拍賣系統,預設隔離等級下兩個用戶同時出價可能接受較低的價。怎麼解?
預設 Read Committed 下,兩交易可能都在對方 commit 前讀到相同最高價 → 較低出價被錯誤接受。兩個解法:
- Row-Level Locking(首選):
SELECT maxBid FROM Auction WHERE id=123 FOR UPDATE鎖住該行,其他FOR UPDATE必須等 - 更高隔離等級:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE(防所有異常,但衝突需重試)
面試別只說「我們用交易」,要說「交易加上列層級加鎖」。確切知道鎖哪幾行 → 列鎖;複雜到難預知 → Serializable。
Q9(Analysis):PostgreSQL 的 Repeatable Read 和 SQL 標準有什麼不同?這代表什麼實務意義?
SQL 標準的 Repeatable Read 只防 dirty read + non-repeatable read,仍允許 phantom read。PostgreSQL 的實作更強:在交易開始建一致性快照,同時防 phantom read(即使其他交易提交了符合條件的新行,你也看不到)。
實務意義:很多在別的資料庫需要 Serializable 才能處理的情況,在 PostgreSQL 用 Repeatable Read 就夠,並行度更高、開銷更低。
Q10(Analysis):什麼情況該偏離 PostgreSQL?「需要擴展」是好理由嗎?
「單純需要擴展」不是好理由 —— 設計得當的 PG 能撐相當大規模。真正該偏離的情況:
- 極端寫入吞吐(每秒數百萬寫)→ WAL + 索引更新 I/O 瓶頸 → Cassandra / Redis
- 全球多區域多寫(active-active) → PG 單主架構只能一個 Region 主寫 → CockroachDB / Cassandra / DynamoDB Global Tables
- 純 Key-Value 存取 → MVCC/WAL/planner 是殺雞用牛刀 → Redis / DynamoDB
面試心法:從 PG 出發,說明為何偏離,比從小眾方案出發再證明它更好有說服力。
Part 3:DynamoDB
Q11(Recall):DynamoDB 的 Partition Key 和 Sort Key 各扮演什麼角色?底層怎麼運作?
- Partition Key:值被 hash → 決定 item 存哪個物理分區(概念類似 consistent hashing,但用中心化分區 metadata 服務,非 P2P ring)
- Sort Key(選填):同分區鍵下對 item 排序 → 分區內高效範圍查詢(底層用以 sort key 為索引的 B-tree)
兩層架構 = 水平擴展(hash 分區)+ 分區內高效查詢(B-tree)。選 PK 要均勻分散 + 契合最常見查詢。
Q12(Recall / Analysis):GSI 與 LSI 的關鍵差異?(至少四點)
| 維度 | GSI(全域) | LSI(本地) |
|---|---|---|
| 分區鍵 | 與主表不同 | 與主表相同,不同 SK |
| 儲存 | 獨立分區/獨立複製 | 與 item 共址 |
| 一致性 | 僅最終一致 | 可強一致讀取 |
| 建立時機 | 可隨時新增/移除 | 只能建表時定義 |
| 數量上限 | ≤ 20 | ≤ 5 |
| 吞吐 | 與基表分開計算 | 與基表共用 |
記憶點:GSI 靈活(不同 PK、隨時建)但犧牲強一致;LSI 共址、可強一致但建表時就要規劃好。
Q13(Application):要在 DynamoDB 存 YouTube 觀看數,每秒 1,000 萬次寫入。大約需要多少分區?這帶出什麼架構考量?
每次寫入(不管多小)至少 1 WCU(無條件進位到 1KB),每分區約 1,000 寫/秒 → 約需 10,000 個分區。預置定價(~$0.00065/WCU-小時):10M × $0.00065 × 24 ≈ $15.6 萬/天。
架構考量:定價模型直接帶出架構限制 —— 極高寫入量下 DynamoDB 成本可能爆炸,這正是「成本效益」成為不選 DynamoDB 理由的原因。這種估算能快速判斷方案是否合理。
Q14(Analysis):DynamoDB 的一致性怎麼設定?強一致讀取有什麼限制?
一致性不是表級設定,而是每個讀取請求指定(ConsistentRead):
- 最終一致(預設):任一副本服務,最高可用、最低延遲,0.5 RCU/4KB,表現為 AP/BASE
- 強一致:路由到 leader,反映所有先前寫入,1 RCU/4KB(兩倍),延遲稍高
關鍵限制:強一致讀取不支援 GSI(GSI 只有最終一致),只支援基表與 LSI。設計需強一致的存取模式時必須牢記。另外 DAX 不快取強一致讀取。
Part 4:OLTP vs OLAP
Q15(Recall):為什麼 column-oriented 儲存對分析查詢更快?(三個原因)
三原因疊加:
- I/O 效率:分析通常只需幾個欄位,column 儲存只讀那幾欄,跳過其他;row 儲存必須讀整行 → I/O 可少 90%+
- 壓縮:同欄位型別相同、值域相近,壓縮率遠高於混合行(
status字典編碼 → 每值 2 bit) - 向量化執行:連續同型別資料可用 CPU SIMD 一條指令同時處理幾十個值
Q16(Recall):連接 OLTP 與 OLAP 的三種管線各有什麼取捨?
| 管線 | 機制 | 延遲 | 取捨 |
|---|---|---|---|
| ETL | 定期抽取→轉換→載入 | 小時~T+1 | 簡單可靠;不適合即時 |
| CDC | Debezium 讀 WAL → Kafka → OLAP | 幾秒~幾分 | 近即時;基礎設施複雜 |
| ELT | 先載原始進倉儲,再用 dbt 轉換 | 視排程 | 雲端倉儲算力強,現代主流 |
選擇心法:分析師接受看昨天資料 → ETL 幾乎永遠更好;確認有即時需求才引入 CDC。
Q17(Application):設計 Uber 的分析系統,行程資料怎麼流動?哪些指標不該走 OLAP?
「行程資料寫入 PostgreSQL(OLTP) 供業務使用。透過 CDC 串流到 BigQuery(OLAP),駕駛收入報表、城市供需分析都在 BigQuery 上跑,與線上業務隔離。」
不該走 OLAP 的:需即時監控的指標(例如目前各城市在線司機數)—— 走獨立的 Redis 計數器,因為 OLAP 有分鐘~小時的資料延遲,撐不起即時監控。
Q18(Analysis):什麼時候該用 HTAP 而不是分開建 OLTP + OLAP?代價是什麼?
HTAP 適合:資料量不大(幾十 TB 內)、對分析即時性要求高(無 ETL 延遲)、工程團隊資源有限(免維護資料管線)。代表:TiDB(TiKV row + TiFlash column)、SingleStore。
代價:同時維護兩種儲存格式 → 資源開銷高、複雜度上升、很難對 OLTP 和 OLAP 都做到完全最佳化。當資料超過幾百 TB、或兩種負載模式差異很大,分開建置的效能與成本優勢就很明顯 —— 對大多數規模的公司分開更穩健。
| 問題 | 解法 |
|---|---|
| 怎麼選資料庫 | 需求推導:形狀 → OLTP/OLAP → 規模/一致性,別背比較表 |
| 一般首選 + 何時偏離 | PostgreSQL;極端寫入/全球多寫/純 KV 才偏離 |
| PG 取代哪些專用系統 | GIN→ES、JSONB→Mongo、PostGIS→地理 DB |
| PG 拍賣/庫存競態 | SELECT FOR UPDATE 列鎖(別動不動上 Serializable) |
| PG Repeatable Read 特別處 | 同時防 phantom read(比 SQL 標準強) |
| DynamoDB 主鍵設計 | PK hash 分區 + SK B-tree 範圍,均勻分散 |
| GSI vs LSI | GSI 不同 PK/隨時建/僅最終一致;LSI 同 PK/建表時定/可強一致 |
| DynamoDB 強一致限制 | 不支援 GSI、耗 2 倍 RCU、DAX 不快取 |
| OLTP vs OLAP 儲存 | Row-oriented vs Column-oriented |
| column 為何快 | I/O 效率 + 壓縮 + 向量化(SIMD) |
| ETL vs CDC vs ELT | 先 ETL,確認即時需求再 CDC;現代倉儲流行 ELT+dbt |
| 看到「報表/分析」需求 | 主動把工作負載分離到 OLAP |