nabroux's Obsidian vault, published.

Astro Techbook

語言
中文

Database (SQL vs NoSQL)

my-notes/system-design-hld/concepts · ZH

translationKey: database-sql-vs-nosql #system design #concept

💡 一、資料庫的兩大主流類型

現代系統主要分為兩大資料庫家族:

  • SQL(Relational Databases)關聯式資料庫

  • NoSQL(Non-relational Databases)非關聯式資料庫

兩者的核心差異在於 資料結構、查詢語法、一致性與擴展策略


🧩 二、SQL vs NoSQL 對照表

面向 SQL(Relational) NoSQL(Non-relational)
資料結構 表格(Table)+ 關聯(Foreign Key) 文件、鍵值、圖形或寬欄
Schema 固定結構(定義欄位) 彈性結構(可動態欄位)
查詢語言 SQL(結構化查詢語言) 各自定義(JSON / API)
一致性模型 ACID(強一致) BASE(最終一致)
可擴展性 垂直擴展(Scale-Up) 水平擴展(Scale-Out)
交易支援 強交易支援(Transaction) 多為弱交易或最終一致
適用場景 金融、交易、報表 高併發、快取、文件儲存
代表系統 MySQL, PostgreSQL, Oracle MongoDB, Redis, Cassandra

⚙️ 三、ACID(SQL 資料庫的核心)

ACID 是 SQL 資料庫確保資料正確性的四大原則:

項目 說明 範例
Atomicity 原子性:交易要嘛全成,要嘛全退 轉帳兩步操作不可分開
Consistency 一致性:交易後資料仍符合法則 餘額不能負數、外鍵存在
Isolation 隔離性:交易間不互相干擾 同時查詢不應讀到未提交資料
Durability 持久性:交易成功即永久保存 系統崩潰後仍可恢復

💡 ACID 適用於對資料正確性要求極高的系統: 銀行帳戶、訂單處理、會計報表等。

🧭 四、SQL 資料庫代表系統

🐬 MySQL

  • 最普及的開源 RDBMS。
  • 支援強一致性、交易、索引與 Join。
  • 可使用 InnoDB 引擎(支援 ACID)。
  • 適合:電商後台、金流、傳統 Web 系統。

🐘 PostgreSQL

  • 更嚴謹的 SQL 標準支援與強型別系統。
  • 原生支援 JSON、全文搜尋、GIS。
  • 適合:分析報表、企業級應用、金融系統。
  • 特點:可作為 OLTP + OLAP 混合型資料庫。

🏛️ MySQL vs PostgreSQL 比較

面向 MySQL PostgreSQL
一致性 強一致(InnoDB) 強一致(WAL)
查詢語法 簡潔、普及 標準更完整
JSON 支援 有,但性能較弱 原生 JSONB 類型
擴充性 生態豐富 可自定義類型與函式
適用場景 高流量網站 數據分析與企業應用

🧩 五、NoSQL 資料庫代表系統

🍃 MongoDB(文件導向)

  • 資料以 JSON / BSON 文件格式儲存。
  • 結構彈性(Schema-less),易於快速開發。
  • 支援索引、聚合、Replica Set(具備最終一致性)。
  • 適合:用戶資料、動態內容、內容管理系統。

⚡ Redis(鍵值導向)

  • 基於記憶體的高效快取系統。
  • 支援 String、List、Set、Hash、Sorted Set。
  • 延伸用途:Session 儲存、Queue、Rate Limiting。
  • 支援簡單交易(MULTI/EXEC),但非完整 ACID。
  • 適合:快取、排行榜、分散式鎖(Distributed Lock)。

🧮 六、SQL 與 NoSQL 的取捨思維

系統設計需求 優先考量 建議選擇
交易一致性(金融) 資料正確 SQL(MySQL, PostgreSQL)
高併發、高可用 效能 / 擴展 NoSQL(Redis, MongoDB)
動態結構資料 彈性 Schema NoSQL(MongoDB)
複雜查詢與報表 Join、Aggregation SQL
瞬時資料 / 快取 低延遲 Redis

🔒 七、資料庫鎖機制(Locking)

鎖的目的是防止同時修改同筆資料導致不一致

依照場景分為:悲觀鎖(Pessimistic)樂觀鎖(Optimistic)分散式鎖(Distributed Lock)

1️⃣ 悲觀鎖(Pessimistic Lock)

  • 假設「一定會衝突」,先鎖再操作。
  • 通常在交易開頭就鎖住資料列,其他人要等。
  • 代表語法:
SELECT * FROM users WHERE id=1 FOR UPDATE;
  • 適合高衝突場景(如銀行轉帳)。
  • 缺點:效能較低,會造成等待。

🧠 比喻:

「我先把門鎖上再工作,其他人只能等我做完。」


2️⃣ 樂觀鎖(Optimistic Lock)

  • 假設「大多數情況不會衝突」,只在更新前檢查版本。
  • 常見實作:version 欄位 + CAS(Compare And Swap)
UPDATE users SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 5;
  • 若 version 不符,代表資料已被修改 → 更新失敗需重試。
  • 適合低衝突、高併發的讀多寫少場景。

🧠 比喻:

「我不鎖門,但更新前先確認別人沒動過。」


3️⃣ 分散式鎖(Distributed Lock)

當系統有多台應用伺服器同時存取共用資源(例如 Redis、DB、檔案), 就需要跨節點協調鎖機制。

常見方案:

機制 說明 代表工具
Redis-based Lock 透過 SETNX(set if not exists)實現 Redlock(官方演算法)
Zookeeper Lock 使用 ZNode 建立臨時節點作為鎖 Apache Curator
Database Lock 利用唯一索引或 SELECT FOR UPDATE 模擬鎖 MySQL / PostgreSQL

Redis 分散式鎖範例:

SET resource_lock myid NX PX 30000
# NX = 不存在時才設定
# PX = 鎖過期時間(ms)

🧩 注意事項:

  • 分散式鎖需避免死鎖(lock timeout 機制)
  • Redis 節點故障可能導致鎖失效 → 可搭配 Redlock / quorum 設計

🧠 八、總結

鎖的比較

項目 悲觀鎖 (Pessimistic) 樂觀鎖 (Optimistic)
概念 操作前先鎖 操作後再檢查
實現方式 SELECT ... FOR UPDATE 比對 version 或 timestamp
效能 低(需等待鎖釋放) 高(無阻塞)
一致性 強一致 最終一致(需重試)
適合情境 高衝突(搶購、交易) 低衝突(一般更新)
死鎖風險
實現難度 簡單 較複雜(需應用層控制)

實務設計建議

系統類型 建議用法
銀行轉帳、錢包餘額 悲觀鎖(保證一致性)
用戶設定、個人資料編輯 樂觀鎖(平行度高)
商品庫存(高併發搶購) 一般用悲觀鎖或 Redis 分布式鎖
後台資料編輯 樂觀鎖 + 更新失敗提示(如 Git Merge 概念)

distributed lock

在多台服務(多進程/多容器)同時操作同一份資源(庫存扣減、排程任務、報表產生、上鏈簽名)時,需要一個跨節點的互斥機制,避免併發衝突與重覆執行。

重點 SQL NoSQL
一致性 ACID(強一致) BASE(最終一致)
結構 嚴格 Schema 彈性結構
查詢能力 Join / Transaction 高速簡化操作
擴展 垂直為主(水平也有辦法) 水平為主
鎖機制 內建悲觀 / 樂觀鎖 Redis、Zookeeper 實現分散式鎖
使用時機 金融、交易、報表 高併發、快取、非結構化資料

⚡ SQL vs NoSQL 效能比較與擴展策略說明

🧠 一、哪個效能更好?(這題沒有絕對答案)

✅ 結論先講: 在單機環境下,SQL 通常更快。 在大規模分散式環境下,NoSQL 通常更能撐高併發與吞吐。

兩者的效能差異,不在語法本身,而在於:

  • 資料結構
  • 查詢方式
  • 一致性模型
  • 擴展架構(vertical vs horizontal)

⚙️ 二、效能差異的本質原因

項目 SQL(Relational) NoSQL(Non-relational)
資料組織方式 多表 + 關聯(JOIN) 扁平結構(Document / Key-Value)
查詢模式 複雜查詢 + JOIN 直接取用單筆或集合
交易一致性 強一致(ACID) 弱一致(BASE)
讀寫特性 單機高效、複雜邏輯 分散式高吞吐、簡化邏輯
最佳場景 報表、金融交易、分析 快取、即時服務、內容動態

👉 換句話說:

  • SQL:更適合「複雜查詢」與「強一致」的應用。
  • NoSQL:更適合「高併發、簡單讀寫」的應用。

🔬 三、實際效能比較案例

操作場景 MySQL / PostgreSQL MongoDB / Redis
單筆查詢(索引命中) 約 1~5 ms 約 1 ms(Redis <1ms)
大量 JOIN / 聚合分析 SQL 表現優秀(可用索引、視圖) MongoDB 較慢、Redis 不適合
高併發寫入(>10k ops/s) 難以線性擴展(磁碟 I/O 限制) 水平擴展可線性提升(Sharding)
交易一致性(轉帳) 完整 ACID 須額外實作一致性機制
快取(Session, Token) 效能普通 Redis 極快(in-memory)

💡 總結

  • Redis:效能最高,但資料在記憶體,適合快取與分散式鎖。

  • MySQL/Postgres:單節點性能強,但難撐高併發寫入。

  • MongoDB:結構彈性好,水平擴展容易,效能取決於資料設計。

🧩 四、SQL 為什麼是「垂直擴展(Vertical Scaling)」為主?

🧱 1️⃣ 定義

類型 說明 圖像比喻
垂直擴展 (Scale Up) 升級單台伺服器(CPU、RAM、SSD) 🚀「讓一台機器更強」
水平擴展 (Scale Out) 增加多台伺服器分攤負載 🌐「讓更多機器分工合作」

⚙️ 2️⃣ 為什麼 SQL 傾向垂直擴展?

SQL 資料庫的關聯模型(JOIN、Transaction、ACID) 需要全域一致性與跨表操作,這導致它不容易拆分成多節點。

原因如下:

  1. JOIN 操作必須在同一資料節點進行 → 一旦跨節點,JOIN 成本暴增。
  2. Transaction 要保證原子性 → 需跨表鎖定與同步,跨伺服器時很難維持 ACID。
  3. 索引(B-Tree)為中心化結構 → 拆分會失去全域排序與唯一性檢查。
  4. 一致性模型偏向 CP(Consistency + Partition Tolerance) → 在分散式環境下,通常選擇「暫時不可用」而非「最終一致」。

💡 所以:

SQL 適合「單機高效能 + 強一致性」的設計, 當資料成長時,會先「Scale Up」再考慮「Read Replica / 分片」。

🧮 3️⃣ 而 NoSQL 為什麼容易「水平擴展」?

NoSQL(特別是 Document / Key-Value 型)設計天生具備:

  • 資料之間關聯鬆散(無 JOIN)
  • 操作通常針對單筆 key(簡單查詢)
  • 一致性採 BASE(最終一致)

這讓它能:

把資料**平均分散(Sharding)**到多台機器, 每台節點都能獨立處理請求。

例如:

  • MongoDB → 自動分片(Shard Key)
  • Cassandra → Hash Partition
  • Redis Cluster → Slot-based 分配

🧠 五、真實世界的策略:混合使用

現代大型系統幾乎都採用「SQL + NoSQL 混合架構

資料類型 儲存系統 理由
用戶資料、訂單 MySQL / PostgreSQL 保證交易一致性
快取、Session、排行榜 Redis 極速讀取與過期機制
使用者動態、訊息流 MongoDB / Cassandra 彈性 Schema、高寫入
日誌 / 分析事件流 Elasticsearch / BigQuery 高速查詢與聚合

💬 範例:

Spotify 使用 PostgreSQL 儲存用戶與訂閱資料, 使用 Cassandra 儲存播放紀錄, 使用 Redis 做快取與即時排行榜。

⚖️ 六、總結比較

面向 SQL NoSQL
結構 固定 Schema(表格) 彈性 Schema(JSON、Key-Value)
一致性 強一致(ACID) 最終一致(BASE)
擴展方式 垂直擴展為主 水平擴展為主
效能瓶頸 單機 I/O 限制 網路延遲 / 資料分佈
查詢能力 JOIN、聚合強 單表快、無 JOIN
最適應用 金融、交易、報表 快取、動態內容、高併發
維運難度 結構穩定、操作複雜 分片管理、同步機制複雜
延展性 低(Scale-Up) 高(Scale-Out)

✅ 七、一句話總結

  • SQL 追求「資料正確」 → 單機高效但難分散。

  • NoSQL 追求「系統穩定」 → 分散容易但一致性弱。

🚀 小規模 → SQL 通常更快 🌐 大規模、高併發 → NoSQL 更能撐負載

所以,效能高低不是語法決定的,而是 取決於資料特性、系統規模與一致性需求。

尚無其他語言版本