你在做一個學校系統,資料看起來很普通:學生、課程、成績、老師。有人說「這種就用 SQL」;換成聊天紀錄、商品規格或大量事件資料,又有人說「NoSQL 比較彈性」。再查幾篇文章,還可能看到另一組口訣:SQL 有 schema、NoSQL 沒 schema;SQL 很穩但很難擴充、NoSQL 比較現代而且適合大資料。
問題是,這些說法都把真正的差異壓得太扁。SQL 和 NoSQL 最值得看的,不是哪一個比較新,而是它們如何組織資料、表達關係、支援查詢,以及你願意把哪些複雜度放在哪一層。
先補一個名稱上的小陷阱:SQL 本來是一種語言,不是一種資料庫。平常說「SQL database」時,多半是在指使用 SQL 的 relational database;NoSQL 則是 document、key-value、wide-column、graph 等多種非關聯式資料模型的統稱。
Relational Database:把資料拆成有關係的表
以 PostgreSQL 這類 relational database 為例,資料主要放在 table 裡。每個 table 有 column,每筆資料是一個 row;欄位有明確名稱與資料型別。真正重要的不是「它長得像 Excel」,而是不同 table 之間可以透過 key 建立關係,再用 query 與 join 把需要的資料組合回來。
例如學校系統可以把學生放在 students、課程放在 courses、選課紀錄放在 enrollments。你不需要在每一筆選課資料裡重複學生姓名、班級與所有課程資訊,只要保存相應的 ID,再在查詢時把資料接起來。
├→ enrollments → 成績 / 選課關係
courses ──┘
這種做法很適合關係本身很重要的資料。訂單屬於哪個使用者、付款對應哪張訂單、學生修了哪些課,這些都不是單一物件內部的小細節,而是系統需要長期維護的一致關係。
NoSQL 不是一種資料庫,而是一整群不同模型
NoSQL 常被翻成「非 SQL」,但更實際的理解是:它是一個很大的 umbrella term。document database 會把資料放在文件中;key-value store 以 key 對應 value;wide-column database 用不同方式組織大量欄資料;graph database 則把 node 與 edge 的關係放到資料模型核心。它們彼此之間的差異,有時甚至比其中某一種和 relational database 的差異還大。
最常拿來和 relational database 對比的是 document database。以 MongoDB 為例,一筆資料是一個 document,可以包含巢狀 object 和 array。假設商品規格差異很大,衣服有尺寸和材質,相機有感光元件和鏡頭接環,文件模型可以讓不同商品保留不同形狀,而不必先把所有可能欄位攤成一張巨大表格。
Document:常把一起讀取、一起變動的資料放進同一份 document
「NoSQL 沒有 Schema」其實不準
文件資料庫常被說成 schemaless,但比較精確的說法是schema 可以更彈性。不同 document 可以有不同欄位,不代表資料完全沒有結構,也不代表應用程式可以隨便塞任何東西。MongoDB 本身就支援 schema validation,可以限制欄位型別、允許的值或其他規則。
反過來,relational database 的 schema 比較明確,也不表示每一次需求變動都會很痛苦。schema migration 本來就是正常開發工作;清楚的 constraint 反而能讓錯誤資料更早被擋下來。真正的問題不是「要不要 schema」,而是哪些規則要交給資料庫強制,哪些彈性值得保留。
SQL 也能存 JSON,NoSQL 也不只會存 JSON
資料庫世界的邊界早就沒有教科書對照表那麼整齊。PostgreSQL 是 relational database,但它同時支援 JSON / JSONB;你可以讓核心關係維持在 table 裡,再把比較彈性的 metadata 放進 JSON 欄位。這不會讓 PostgreSQL 突然變成「NoSQL database」,只代表現代資料庫會吸收不同模型的實用能力。
同樣地,NoSQL 也不等於 JSON。Redis 類型的 key-value model、Cassandra 類型的 wide-column model、Neo4j 類型的 graph model,都不是單純「把 JSON 丟進資料庫」可以概括。
Join 和 Embedding:關係要在查詢時組,還是先放在一起?
這是資料建模真正有感的差異之一。Relational design 常把重複資料拆開,透過 foreign key 與 join 在查詢時組合。Document model 則常考慮 access pattern:如果一組資料幾乎總是一起讀、一起改,可能直接把它們 embed 在同一個 document 裡。
例如一篇文章底下只有幾個固定的小設定,把設定嵌在文章 document 裡可能很自然;但如果是一個使用者有數十萬筆交易,而每筆交易又會被獨立查詢、稽核和修改,把所有交易塞進使用者 document 就會變得很不合理。
選資料模型時,先看 access pattern。「資料在現實世界裡屬於同一個東西」不代表它們在資料庫裡就一定要存成同一筆。
Transaction 不是 SQL 的專利
另一個常見誤解是「SQL 有 transaction,NoSQL 沒有」。很多 relational database 的確把 transaction 與 ACID guarantee 放在核心位置,這也是它們很適合處理付款、庫存、帳務與多筆相關更新的原因之一。但這不是說 NoSQL 類資料庫天生不能做 transaction。
MongoDB 目前就支援跨多個 document、collection 甚至 database 的 transaction。只是某項功能「存在」,和它是不是你的資料模型最自然、成本最低的做法,是兩回事。MongoDB 官方資料建模文件也強調,良好的 document model 常會利用單一 document update 的 atomicity,避免把每個操作都做成大型分散式 transaction。
所以不要用「需不需要 transaction」一題就直接決定 SQL 或 NoSQL。更好的問題是:你的 transaction boundary 到底在哪裡?哪些資料必須一起成功或一起失敗?
「NoSQL 比較會 Scale」也太簡單
NoSQL 的流行確實和大型分散式系統有很深的歷史關係,一些系統從一開始就針對 partition、replication 與 horizontal scaling 設計。但今天把「SQL = vertical scale、NoSQL = horizontal scale」當成鐵律已經不準。現代 relational database 也有 replication、partitioning、sharding 與分散式實作;不同 NoSQL 系統的 scale 特性也差非常多。
真正需要評估的是你的 workload:讀多還是寫多、資料量成長速度、是否跨區域、查詢是否需要複雜 join、可接受的一致性與延遲、團隊能不能維運那套架構。資料庫類型不是效能保證書。
那到底怎麼選?先從資料和查詢開始
如果你的核心資料之間有大量明確關係,需要 constraint、join、複雜查詢與一致的 transaction boundary,relational database 往往是很自然的起點。如果資料形狀差異很大、常以完整 document 為單位讀寫,或某種特定 NoSQL model 正好貼近問題本身,那 NoSQL 可能更直接。
例如成績、訂單、付款、權限這類資料,關係通常非常重要;商品 catalog、內容 metadata 或事件資料則可能有比較多變動欄位。但這些都不是硬規則。同一個產品甚至可以同時使用 PostgreSQL 保存核心交易資料、Redis 做快取,再用搜尋引擎或 document store 處理另一種 workload。這種做法通常叫 polyglot persistence:不是硬選一個陣營,而是讓不同資料系統負責適合自己的問題。
最後真正該記住的是資料模型,不是陣營
SQL / NoSQL 的比較很容易變成技術宗教戰,但做產品時比較有用的問題其實很樸素:資料有哪些實體?彼此怎麼關聯?哪些東西會一起讀寫?哪些規則不能被破壞?最常做什麼 query?未來資料量和流量會怎麼長?
當這些問題回答得夠清楚,資料庫選擇通常會比「哪個比較快」「哪個比較新」容易很多。SQL 與 NoSQL 不是前後世代,而是不同資料模型、查詢能力與系統取捨的集合。
如果只想先留一句:不要先選資料庫,再逼資料配合它;先理解資料和 access pattern,再決定哪個模型比較自然。
資料來源
Relational table、row、column 與 join 的說明參考 PostgreSQL Concepts 與 Joins Between Tables;PostgreSQL 的 JSON / JSONB 與 transaction 能力參考 PostgreSQL 官方介紹。Document data model、schema validation 與 multi-document transaction 則參考 MongoDB 官方的 Data Modeling、Schema Validation 與 Transactions 文件。