資料模型起手式:關聯式 vs 文件式
同一份資料,換一種「組織術」,整個系統的命運就不一樣
語言的界線,就是世界的界線
第二章一開頭,作者沒有先丟術語,而是引了一句哲學家的話當題詞。乍看跟資料庫沒關係,但讀完整章你會發現它其實是核心隱喻:你選的 資料模型, 就是你能用來「描述世界」的語言——選錯語言,有些事情你連說都說不出來。
「我的語言的界線,就是我的世界的界線。」
——維根斯坦,《邏輯哲學論》(1922)
資料模型很可能是開發軟體時最重要的一環,因為它的影響極其深遠:不只決定程式怎麼寫,還決定我們怎麼「思考」眼前要解決的問題。
把資料模型想成你經營的「餐飲帝國」裡,從顧客點餐心願到餐桌上菜的整套組織術:顧客的心願要變成服務生的點菜單,點菜單要變成廚師看得懂的食譜,食譜又要變成倉庫裡實際擺放的食材。每一層都是一次「翻譯」,而抽象化就是讓你不用管底層怎麼運作的魔法。
資料的「變身」之旅:從心願到電流
你的資料不會直接從現實世界跳進硬碟。它會經過好幾層翻譯,每一層都比下一層更簡潔、更抽象。
顧客腦中那句「我要一份客製化義大利麵,少辣多起司」——人、組織、商品、行為,原汁原味的需求。
服務生把心願寫成標準化的點菜單:欄位記錄菜名、辣度、起司量。這是你程式碼裡的物件與 API。
廚師不看點菜單做菜,他照通用資料模型(套餐式、食材清單式、關係圖譜式)來理解——這正是本模組的主角:關聯式 vs 文件式。
庫房經理把抽象的「起司」變成「一塊 500 克的高達,放在 B 區冷凍櫃第三層」——資料庫工程師把模型轉成記憶體與硬碟上的位元組。
每種資料模型都內建「預設的使用情境和假設」——選對了,某些操作快得不可思議;選錯了,同樣的操作可能慢到難以忍受,甚至根本做不到。這就是為什麼整本書要花一整章講這件事。
兩大典範,點開看懂彼此的脾氣
第二章的主戰場,就是這兩種通用資料模型的較量。點點看,比較它們的定義與最適合的情境。
用一個比喻分高下:關聯模型像超級圖書館的標準化檔案系統——每個主題分區放好,靠「讀者編號」「ISBN」這類唯一識別碼互相牽線;文件模型則像你的私人日記——一天的行程、心情、照片全寫在同一頁,翻開就是全貌。
文件模型多半是Schema-on-read,今天能塞流水帳,明天能貼照片,事後看得懂就好;不必像關聯式那樣每次改格式都要動全資料庫的表格。
相關資料整包存在一起,一次讀取就拿到全貌——像做三明治時食材全放同一個籃子,伸手就拿,不用跑冰箱又跑櫥櫃。
JSON 文件的樹狀結構天生就接近你程式裡的物件,能有效減少把物件拆進表格、再從表格組裝回物件的麻煩翻譯。
關聯式怎麼運作:表格、鍵、JOIN
關聯模型靠三個角色撐起整套系統:主鍵讓每筆記錄獨一無二,外鍵把不同表格串起來,JOIN則是真正把資料兜在一起的「連接器」。
你只需要告訴資料庫「我要什麼」,不用管「怎麼找」——這叫宣告式查詢。底層有個「查詢最佳化器」,像圖書館智能查詢機背後的大腦,自動規劃最快的路徑。這正是關聯模型加上 SQL 能稱霸資料庫世界幾十年的關鍵:你少操心「怎麼做」,資料庫升級了索引或執行策略,你的查詢一行都不用改就能變快。
你的程式碼習慣用物件思考——一個使用者物件裡塞著姓名、工作經歷、學歷。但存進關聯式資料庫前,得先把它「拆解」成 users、positions、education 好幾張表格,讀出來時再「組裝」回物件。這種來回翻譯的麻煩,就是阻抗不匹配——這正是文件模型想解決的痛點。
文件模型怎麼運作:自包含、彈性、貼近物件
文件模型的興起,是NoSQL運動的一部分,背後三個推力:資料量與併發暴增、開發節奏要求 Schema 能跟著快速迭代、以及前面提到的阻抗不匹配。一份 JSON 文件就能把使用者的姓名、工作經歷、學歷全部打包在一起——自包含、可以是多層樹狀結構,特別適合表達「一對多」關係,例如一個人有多份工作經歷。
但文件模型不是萬靈丹。它在處理「多對多」關係時通常比較吃力——如果你的資料常需要在多個實體之間頻繁地「跳轉」查詢(例如找出某供應商相關的所有訂單,再找出這些訂單裡所有顧客的詳細資料),關聯模型的 JOIN 反而更得心應手。
很多大型應用會讓不同部分的資料用不同模型存——這叫「多模型持久化(Polyglot Persistence)」。例如使用者個人檔案用文件模型、課程先修關係用圖形模型、測驗排名用關聯模型。選型不是信仰之爭,是看資料的形狀和你最常做的操作。
小試身手
兩種典範的脾氣摸得差不多了,來兩題檢查一下:
關聯與文件兩大家族各有優點,但現實世界的資料常常兩邊都要——接下來看看這種「兩難」會踩到哪些坑。
物件關係不匹配:資料組織的兩難
程式碼愛用「物件」、資料庫愛用「表格」——當兩種方言互相翻譯,你得學會挑邊站
兩種「方言」,同一份履歷
你的程式碼裡,一個使用者是一顆完整的 物件 ——姓名、頭像、底下還掛著一串工作經歷、一串學歷。但資料庫裡的 關係型資料庫 只認得「表格」:一張 users 表、一張 positions 表,彼此用 id 互相指。這種結構上的落差,書裡稱為 物件關係不匹配。
今天大多數應用程式都是用物件導向語言寫的,這帶來一個對 SQL 資料模型常見的批評:如果資料存在關係型表格裡,程式碼裡的物件跟資料庫的表格、列、欄之間,就需要一層彆扭的轉換。
這種模型之間的落差,有時被稱為「阻抗不匹配」。
像 ActiveRecord、Hibernate 這類 ORM 框架,能減少這層轉換需要寫的樣板程式碼,但沒辦法完全藏住兩種模型之間的差異。
然而,大多數人一生不只做過一份工作(多段工作經歷),教育背景的期數也因人而異,聯絡方式更可能有好幾筆。
使用者跟這些項目之間,是一種一對多的關係。
你跟服務生說「我要一份主廚特製套餐」,但後廚的庫存系統只認得「牛排一份」「蘑菇湯一碗」這種單一品項——套餐是你腦中的完整想像,後廚卻只懂拆開來的食材清單。這就是物件與表格的「方言差異」。
用 LinkedIn 個人檔案拆給你看
想像一份 LinkedIn 履歷:姓名、自我介紹是「一人一筆」的簡單欄位,但「工作經歷」「學歷」「聯絡方式」卻是「一人好幾筆」——這就是 一對多關係。 物件導向程式碼很自然地把它們都包進同一個 UserProfile 物件裡,變成一棵樹;但關係型資料庫為了 正規化, 會把它拆成 users、positions、education 三張各自獨立的表格,用 user_id 當外鍵互相指認。
一個 UserProfile 物件,底下直接掛著 positions 清單、education 清單——一次拿到、一次看完。
users、positions、education 各自一張表,靠 user_id 這個外鍵互相連結,沒有人「整包」存。
先查 users 拿到基本資料,再用 user_id 分別查 positions、education,最後在程式碼裡手動拼回一個完整物件。
ORM 就像餐廳的服務生:把你的「套餐」訂單(物件)拆成後廚聽得懂的單品指令(多張表的 SQL 操作),出餐時再把零散菜色組裝回一份套餐端給你。它能省去大量手動翻譯的力氣,但沒辦法讓兩種「方言」變成同一種——差異還是在,只是被藏起來一部分。
換個容器:文件資料庫的「便當盒」解法
如果餐廳改賣「客製化便當盒」呢?你點的整份套餐直接打包成一盒——這就是 文件型資料庫 的概念。一個 UserProfile 物件,可以直接存成一份 JSON 文件,positions、education 都內嵌在裡面,讀的時候一次整份拿出來,幾乎不用「翻譯」。
但便當盒也有它的麻煩:如果某道菜(例如「公司」)本身是個獨立實體,需要被很多份履歷共用、又要隨時更新最新 logo,那把它直接寫死在每份便當盒裡,就會重新製造出「資料重複」的問題——這正是 資料在地性 換來的代價:跨文件的複雜關聯,文件資料庫天生不擅長。
資料拆開存、靠外鍵連結,正規化程度高,多對多關聯靠 JOIN 一次處理得漂亮。
整包存在一起,貼近程式裡的物件樹狀結構,一次讀取就拿到全部,但跨文件關聯較吃力。
履歷內嵌進文件可以解決「一人多筆工作經歷」這種一對多關係;但如果「公司」要變成有自己頁面、能被搜尋、能被多人引用的獨立實體,文件模型反而要在應用程式層自己模擬關聯查詢,相當繁瑣。
動手選一選:這種資料情境,該用哪種因應策略?
下面四種常見的資料情境,各自比較適合哪種因應策略?拖拖看,配完按「對答案」。
另一道兩難:先檢查再存,還是先存再說?
除了「物件 vs 表格」,資料模型還有第二層選擇:資料的 Schema 要在「寫入前」就嚴格把關,還是「讀取時」才由程式自己解讀?
Schema-on-Write 像超市進貨——倉管會逐項核對品名、規格,不合規格直接拒收,不讓它進倉庫。 Schema-on-Read 則像超市結帳——你把什麼都丟進購物車都行,店員直到結帳掃描那一刻,才需要搞懂你買了什麼。
寫入超自由,彈性高,適合原型開發、IoT 感測資料、日誌這種結構常變、來源混雜的場景。代價是讀取時得自己處理「缺欄位」「舊格式」這種異質資料。
寫入前就把關,資料品質、一致性有保證,適合金融交易、庫存、權限這種高一致性需求。代價是要改結構時,得規劃遷移(migration),成本較高。
Schema-on-Write 要改結構,得像搬家一樣規劃:新增欄位、搬資料、確認沒問題才能拆舊欄位。Schema-on-Read 則把這份麻煩往後拖到「讀取那一刻」,由程式自己判斷舊資料該怎麼解讀——彈性和一致性,永遠是一場交換。
小試身手
物件、表格、文件、Schema 的兩難,你抓到核心了嗎?來兩題。
講完「資料長什麼樣子」,接下來換個角度——你要怎麼「問」資料庫問題?往下捲,進入查詢語言的世界。
查詢語言大解密:SQL 與 MapReduce
「教廚師怎麼做菜」還是「直接點菜」——兩種跟資料庫對話的風格,決定了誰來操心效能
跟資料庫溝通,其實只有兩種口氣
前面兩站我們搞懂了資料「長什麼樣子」——關聯式的表格、文件式的巢狀結構。這一站換個角度:資料擺好之後,你要怎麼「問」它問題?
說也奇怪,幾乎所有跟電腦對話的方式,攤開來看都只有兩種口氣。一種是 命令式 ——你像個事必躬親的將軍,一步步下令「先做這個、再做那個」;另一種是 宣告式 ——你只說出你想要的結果,剩下的細節丟給系統自己想辦法。
命令式,就像你親自走進廚房,告訴主廚「先拿雞肉、切丁、熱鍋、炒到半熟、加番茄醬燉十五分鐘」——每個動作都你說了算。宣告式,就像你坐在餐桌前翻菜單,只說「我要一份經典番茄燉雞」,主廚(也就是資料庫的 查詢優化器 )會自己判斷最快、最好的做法。
直接讀原文,旁邊就是白話
書裡用一段很乾脆的對比,把「宣告式」講得很透徹——尤其是它「藏起怎麼做」反而帶來的好處。一句對一句看:
命令式語言會叫電腦照特定順序執行某些操作。
你可以想像成一行一行讀過程式碼:判斷條件、更新變數、決定要不要再跑一次迴圈。
而像 SQL 或關聯式代數這種宣告式查詢語言,你只要指定你想要的資料長什麼樣子……不必說「怎麼達成」。
該用哪個索引、用哪種聯結方式、查詢的各部分要照什麼順序執行——這些都交給資料庫的查詢優化器自己決定。
宣告式查詢語言之所以吸引人,是因為它通常比命令式 API 更簡潔、更好駕馭。
你可能覺得「藏起怎麼做」是失去掌控權,但書裡的重點剛好相反——正因為你沒寫死步驟,資料庫日後想換更快的演算法、加新索引,甚至把查詢拆成多核心並行跑,都不必驚動你的程式碼一行。
同一個任務,兩種寫法:找出所有「鯊魚」
說再多比喻,不如看一次真正的程式碼。假設有一份動物清單,我們想找出所有 family 是「Sharks」的動物——兩種風格的程式碼,長相完全不同。
先準備一個空籃子,逐一檢查每隻動物,符合條件就放進去,最後把籃子交出來——每個動作都得你來寫。
SELECT * FROM animals WHERE family = 'Sharks'; ——一句話講完「我要什麼」,怎麼找、要不要用索引,資料庫自己決定。
命令式在處理複雜、特殊的流程控制時依然有它的彈性;只是對「找符合條件的資料」這種常見任務,宣告式通常更簡潔、更好維護,也更容易被資料庫拿去自動優化、甚至平行處理。
SQL 的三招「許願術」
SQL(Structured Query Language)是宣告式查詢語言裡最經典的代表。你不需要懂資料庫內部怎麼運作,只要學會「怎麼許願」。以一個學生成績系統為例:
SELECT name, score FROM students WHERE gender = 'Female' AND score >= 90; —— 只說條件,資料庫負責找。
SELECT class_id, AVG(score) FROM students GROUP BY class_id; —— 一句話算出每班平均,不必自己寫迴圈分類加總。
SELECT s.name, c.class_name FROM students s JOIN classes c ON s.class_id = c.id; —— 把兩張表「接」起來看,細節交給資料庫。
每一句 SQL 背後,查詢優化器都在悄悄分析:該用哪個索引、先查哪張表、要不要拆成多核心並行——這正是命令式程式很難自動做到的事,因為步驟早就被你寫死了。
MapReduce:界於命令式與宣告式之間的「分工合作」
那文件資料庫呢?像
MapReduce
這種工具,介於兩種風格中間——你得自己寫 map 和 reduce 兩段 JavaScript 函式,但拆分、分組、平行執行的工作仍由系統代勞。拆開看,其實就是三個動作:
對每一筆觀測紀錄執行 map 函數:如果 family 是「Sharks」,就把「年-月」當作鍵,把數量發出去。
emit(key, value) 把這筆結果連同它的鍵值對交出去,系統會自動把相同鍵的值集中放在一起,準備交給下一階段。
對每個分組鍵執行 reduce 函數,把同一個「年-月」底下所有的數量加起來,得到那個月的鯊魚總數。
它們不能偷偷修改外部狀態,也不能在裡面另外查資料庫——這條規矩聽起來很硬,卻是換來安全感的代價:系統才能放心把工作切成一塊塊平行處理,就算某一塊失敗了,重跑一次也不會搞亂結果。
正因為自己寫 map/reduce 比較繁瑣,後來 MongoDB 這類資料庫又推出了更宣告式的
聚合管線(Aggregation Pipeline)
——用 $match、$group 這些階段組成一條生產線,寫法更接近 SQL,也更容易被資料庫自動優化。
小試身手
分清楚「誰在說怎麼做、誰只說要什麼」,你就抓到這一站的核心了。來兩題:
SELECT * FROM animals WHERE family = 'Sharks'。下列敘述何者正確?關聯式與文件式模型,骨子裡都還是「表格/樹狀」思維——就算查詢語言再聰明,遇到「朋友的朋友」這種錯綜複雜的多對多關係,還是會堆出一大堆 JOIN。如果資料本身就長得像一張關係網呢?往下捲,進入圖形資料模型。
圖形資料模型:Cypher、SPARQL、Datalog
當資料長得像一張錯綜複雜的關係網,「點」和「線」會比表格更誠實
當「多對多」多到爆炸,表格會先喊累
前面幾站我們看過關聯模型和文件模型怎麼處理一對多、甚至簡單的多對多關係。但如果你的應用裡,幾乎「每樣東西都跟很多別的東西有關係」——朋友的朋友、誰住在哪裡又屬於哪個國家、誰買了同系列的哪些商品——關聯模型就算還能硬撐,也會堆出一大堆 JOIN,越查越慢、程式碼越寫越擰巴。
這種「高度互聯」的資料,換一種想法會自然很多:把每樣東西都當成頂點,把它們之間的關係畫成一條條邊——這就是圖形資料模型。
你的導航 App 就是一個活生生的圖形資料庫。地圖上的地點(你家、咖啡館、公司)是頂點,連接它們的道路是邊;每個地點有自己的營業時間、評價,每條路有自己的長度、路況——這些都是屬性。按下「導航」,App 就是沿著邊一段段「走」,幫你找出最佳路線。
原文怎麼說:document 笨拙、relational 還行、graph 最自然
這句判斷,是整節的核心結論,直接從書裡搬出來給你看:
沒有哪個資料模型「天生比較簡單」這回事——關鍵看你的資料之間到底有什麼樣的關聯。
如果資料高度互聯:文件模型會很笨拙,關聯模型勉強能接受,圖形模型則是最自然的選擇。
一張圖由兩種東西組成:頂點(也叫節點或實體),以及邊(也叫關係)。
圖形還有一個同樣強大的用法:把完全不同種類的東西,全部一致地存進同一個資料庫裡。
書裡沒有說圖形資料庫贏過一切——它只在「關係本身就是重點」的情境裡最自然。員工薪資表這種彼此獨立的資料,關聯式資料庫照樣輕鬆。
招牌互動:拆開一張屬性圖(Property Graph)
屬性圖模型是最直觀的圖形資料模型,由 Neo4j 這類資料庫實作。它就三個零件,點開每一個看看定義:
把每個人想成一份檔案(頂點),檔案裡寫滿姓名、職業(屬性)。當兩人有關係,就在兩份檔案之間畫一條線(邊),線上貼著「朋友」這種標籤,旁邊還能寫「認識日期:2020 年」(邊的屬性)。要追查某人的社交圈,直接從他的檔案沿著線往外查就好。
還有一種相近但更「原子化」的模型,叫三元組儲存:把每件事都拆成「主詞、謂詞、受詞」三段式陳述,例如 `(lucy, age, 33)`、`(lucy, marriedTo, alain)`。謂詞既可以是屬性鍵,也可以是邊的關係類型——本質上跟屬性圖是同一件事的另一種寫法。
跟著查詢走一遍:朋友的朋友的朋友
Cypher 是屬性圖專用的查詢語言,語法就像在「畫」一張關係圖:`(a)-[:FRIEND_OF]->(b)` 一眼就懂。下面按「下一步」,看資料庫怎麼沿著邊,從小明一路走到他朋友的朋友。
同樣這個查詢,關聯式資料庫得對「朋友關係」這張表自己 JOIN 自己兩次(甚至更多次),才能走兩步關係。圖形資料庫把「邊」當成第一級結構,沿著邊走訪天生就快、天生就好寫。
三種「魔咒」,同一種精神:宣告式
Cypher、SPARQL、Datalog 都是宣告式查詢語言——你只描述「想要什麼樣的關係模式」,剩下交給資料庫自己找最佳路徑去走。就像點菜,你說「我要一份義大利麵」,不用教廚師怎麼煮。
頂點用 `()`、邊用 `-[]->`。`(lucy)-[:BORN_IN]->(idaho)` 一看就懂是「Lucy 出生在 Idaho」。專為屬性圖設計,Neo4j 的查詢語言。
專為三元組儲存設計,用一串「主詞 謂詞 受詞」陳述句描述已知條件,例如 `?person :bornIn ?place`,再讓資料庫拼出符合的答案。
Cypher 的 `[:WITHIN*0..]`、SPARQL 的 `:within*`,都能表達「沿著這種關係,走 0 次或多次」——城市在州裡、州在國裡,不管疊幾層都一次查完,SQL 得寫死固定次數 JOIN 才能逼近。
書裡的例子「找出所有從美國移民到歐洲的人」:Cypher 寫成 `(person)-[:BORN_IN]->()-[:WITHIN*0..]->(us)` 配上 `LIVES_IN` 那一半;SPARQL 則寫成 `?person :bornIn / :within* / :name "United States"`。語法不同,講的是同一件事——沿著「位於」關係一路往上找,不管中間隔幾層。
Datalog:用「事實+規則」推理出答案
Datalog 不像 Cypher、SPARQL 那麼家喻戶曉,卻是它們的靈感源頭。它的世界只有兩種積木:事實和規則。規則能從已知事實一路「推導」出新事實,特別擅長處理像家譜樹這種層數不固定的結構。
不需要推論、本來就確定的資訊。例如 `name(idaho, 'Idaho')`、`within(idaho, usa)`——就是偵探手上的筆錄。
「如果前提成立,結論就成立」。`within_recursive(L,N) :- within(L,Via), within_recursive(Via,N)` 讓「位於」可以一層層往上疊。
規則引用自己,像俄羅斯娃娃一層包一層,自動涵蓋「不知道有幾層」的祖先、行政區劃,不用事先寫死層數。
事實=已知線索;規則=偵探腦中的推理法則;查詢=偵探想知道的問題。給定 `parent(Alice, Bob)`、`parent(Bob, Carol)` 和規則 `grandparent(X,Z) :- parent(X,Y), parent(Y,Z)`,引擎會自己湊出 `grandparent(Alice, Carol)`——這個新事實,沒有人手動寫過。
小試身手
圖形模型、屬性圖、Cypher、Datalog 都認識了一輪,來兩題檢查一下:
四種模型——關聯式、文件式、查詢語言、圖形——全部攤開來,到底什麼情境該選誰?往下捲,幫你的下一個專案做決定。
大局:三種資料模型怎麼選
關聯、文件、圖形——不是誰比較先進,是誰比較懂你的資料長什麼樣
把整章倒帶一次:你其實學了一條「翻譯鏈」
這一章繞了一大圈,其實都在講同一件事:你腦中的真實世界概念,要經過好幾層 抽象化, 才能變成硬碟裡的位元組。每一層都用自己的 資料模型 說話——應用程式講物件,資料庫講 JSON/表格/圖形,硬體講電流脈衝。
而我們在中間這一層「通用資料模型」,其實只有三個主要選手反覆出現:關聯式、文件、圖形。這個模組不會再逐一教細節,而是把它們攤開來放在同一張桌上,幫你建立「什麼情境選什麼」的判斷力——這是你讀完整章最值錢的能力。
沒有一種資料模型是「正解」,只有「跟你的資料形狀match不match」。選錯不會馬上爆炸,但會讓你之後每一個查詢都在跟模型「對抗」。
書裡是怎麼收尾這個選擇題的
原文在談完關聯式與文件模型的拉鋸後,用一段話把「什麼時候該換成圖形模型」講得很乾脆。直接看原文,旁邊配白話。
前面看到了:「多對多關係」是區分不同資料模型最關鍵的特徵。
如果你的應用大多是「一對多」(樹狀結構),或紀錄之間根本沒什麼關係,文件模型就很合適。
但如果你的資料裡,多對多關係非常普遍呢?
關聯模型能應付簡單的多對多,但當資料裡的連結越來越複雜,把它建模成「圖形」會自然得多。
一個圖形,由兩種東西組成:頂點(也叫節點、實體)和邊(也叫關係)。
樹狀、自成一體 → 文件;關係明確但不太複雜、要強一致性 → 關聯;關係本身就是重點、而且盤根錯節 → 圖形。整章其實就是在教你認出這三種「形狀」。
三選手並排站:點點看,每個的「個性」是什麼
把整章學到的三種通用資料模型放在同一張圖上。點下去看每個的白話總結。
PostgreSQL 加了 JSONB 欄位,MongoDB 加了 聚合管線, 兩邊都在互相學習。但這不代表它們變成同一種東西——選型時還是要回到「我的資料、我的查詢模式,骨子裡比較像哪一種形狀」。
整章總複習:把情境拖到對的資料模型上
這是這個模組的招牌互動。下面四個應用情境,憑你對整章的理解,拖到它最自然的資料模型。有一題刻意設計成「兩種模型都說得通」,留意選項說明。
「商品推薦關係」一開始用關聯模型存簡單的多對多完全沒問題;但隨著推薦邏輯越長越複雜、關係層層交織,書裡說得很白:這時候「自然地」會開始把資料建模成圖形。模型不是一輩子綁死的選擇。
整章關鍵字快閃複習
四個你在整章反覆遇到的概念,最後再串一次:
阻抗不匹配提醒我們:選模型不只是選資料庫,也是選「跟你程式碼合不合拍」。
不管選哪種資料模型,宣告式查詢(像 SQL、Cypher)都讓你專注在「要什麼」,把「怎麼做」交給查詢優化器。
大型系統常常不只用一種模型——這節課看到關聯式資料庫長出 JSON 支援、文件資料庫長出 join,界線一直在模糊。
一對多選文件,簡單多對多關聯也行,但頂點與邊串起來的複雜關係,圖形模型最吃得開。
整章總複習:兩題定生死
這兩題故意跨小節出,看看你是不是真的把「選型判斷力」內化了。
資料怎麼「長」出來了——你現在會挑形狀、會選模型。下一步是:它實際怎麼被儲存與找到?我們要鑽進儲存引擎的底層,看資料庫收到一筆寫入之後,到底把它放在硬碟的哪裡、又是怎麼幾毫秒內把它翻出來。