前言:如何使用本教材
大多數人學資料庫,是從 SQL 語法開始,最後也停在 SQL 語法。本教材的目標不同:我們要回答的是 「資料庫到底是怎麼運作的」——當你輸入 SELECT * FROM users WHERE id = 123;,從字串被解析、計畫被選出、頁面從 SSD 讀進緩衝池、 MVCC 判定哪個版本可見、到交易提交時 WAL 被刷到磁碟,每一步究竟發生了什麼事。
閱讀文章 →關聯模型與關聯代數
1970 年 E. F. Codd 在〈A Relational Model of Data for Large Shared Data Banks〉中提出: 應用程式不應該知道資料在機器內部怎麼排列。當時主流的階層式(IMS)與網狀式(CODASYL)資料庫, 程式必須沿著指標「導航」才能取得資料,一旦實體佈局改變,程式就得重寫。 Codd 的答案是把資料抽象成數學上的關聯(集合論中的 relation), 讓使用者只描述「要什麼」,
閱讀文章 →儲存引擎與頁面佈局
資料庫是「以磁碟為導向(disk-oriented)」的系統:資料的主要住所是非揮發性儲存裝置, 記憶體只是暫存。因此所有資料結構的設計目標都是減少磁碟 I/O 次數,而非減少 CPU 指令數。 要理解這一點,先看各層儲存的延遲差距:
閱讀文章 →B-Tree、B+Tree 與索引
Bayer 與 McCreight 在 1972 年提出的 B-Tree 把「節點」放大成「一整個頁面」: 每個節點放數百個鍵,樹高降為 _f N(f 是扇出)。f = 400、N = 10^9 時高度只有 4。
閱讀文章 →Buffer Pool
資料庫不可能每次存取都讀磁碟。Buffer pool(又稱 buffer cache、buffer manager)是記憶體中一塊由資料庫 自己管理的頁面快取,位於執行引擎與磁碟之間:
閱讀文章 →查詢執行
Parser 分兩層:詞法分析(lexer)把字串切成 token(關鍵字、識別字、常數、運算子), 語法分析依文法規則組成抽象語法樹(AST)。以 SELECT name FROM users WHERE age > 30 為例:
閱讀文章 →查詢最佳化
SQL 是宣告式語言:使用者說「要什麼」,系統決定「怎麼做」。同一個查詢的不同實體計畫,執行時間可以相差好幾個數量級—— 例如 10 表 join 的左深計畫有 10! 3.6 × 10^6 種排列,再乘上每個 join 的演算法與存取路徑選擇。 最佳化器的目標並非找到最佳計畫(那本身就是 NP-hard),而是在可接受的時間內避開糟糕的計畫。
閱讀文章 →交易與 ACID
交易transaction是一組被視為單一工作單位的資料庫操作:要嘛全部生效,要嘛全部不生效。 它是資料庫對應用程式最重要的抽象——讓開發者在面對當機與並行時,仍能以「一次只有我在操作、而且操作不會做到一半」的方式思考。
閱讀文章 →預寫式日誌(WAL)
第 4 章提到緩衝池的 steal(未 commit 的髒頁可先寫回)與 no-force(commit 時不必寫回資料頁)策略能把隨機寫入延後、合併, 但也帶來兩個問題: 解法是把「發生了什麼修改」循序追加到一個獨立的日誌檔並 fsync——循序寫比隨機寫快一到兩個數量級, 而且一次 fsync 就能讓一批交易持久。資料頁本身可以晚點、合併後再寫。這就是 預寫式日誌Write-Ahead Logging, WAL。
閱讀文章 →多版本並行控制(MVCC)
鎖式並行控制(第 10 章)讓讀者與寫者互相阻塞。多版本並行控制Multi-Version Concurrency Control, MVCC 改變規則:寫入不覆蓋舊值,而是產生新版本;每筆交易讀取一個固定時間點的快照。於是: 代價是:空間(舊版本)、回收舊版本的工作(garbage collection)、以及索引必須處理多個版本。 任何 MVCC 實作都要回答三個問題:版本存哪裡?讀者如何判定可見?舊版本何時回收?
閱讀文章 →鎖與並行控制
最基本的兩種模式:共享鎖 S(讀)與排他鎖 X(寫)。若鎖的粒度是整張表,並行度太低;若只有列鎖, 一個全表掃描要取百萬個鎖,鎖表爆炸。Gray 等人(1976)提出多粒度鎖與意向鎖(intention lock): 在上層節點(資料庫 表 頁 列)宣告「我打算在下層取某種鎖」。
閱讀文章 →當機復原與 ARIES
復原演算法的目標是在系統當機後恢復 原子性(未 commit 的交易效果消失)與持久性(已 commit 的交易效果存在)。
閱讀文章 →LSM-Tree
B+Tree 的每次更新都是原地修改一個頁面:即使只改 100 bytes,最終也要把整個 8–16 KB 的頁寫回磁碟(寫入放大 80–160 倍), 而且這些頁散佈各處,是隨機寫入。在 HDD 時代這是尋道瓶頸,在 SSD 上則加速磨損並放大 FTL 內部的垃圾回收。 隨機寫入的另一個代價:每頁寫入前都要取 latch、處理分裂、寫 WAL。
閱讀文章 →行式儲存與 OLAP
第 1 章區分過兩種負載:OLTP 以主鍵存取少數列的全部欄位並頻繁更新;OLAP 掃描上億列但只碰少數欄位,做聚合,幾乎只讀。 用列式(row-oriented,NSM)儲存跑 OLAP 有三個根本問題:
閱讀文章 →分散式資料庫基礎
單機資料庫在三個方向上會碰到天花板:規模(資料量或吞吐超過一台機器)、可用性(一台機器當機就全停)、 延遲(使用者分佈全球,光速往返 150 ms)。分散到多台機器解決這些問題,代價是必須面對分散式系統的三個根本事實: 本章處理資料的擺放(複寫與分割)與一致性語意;第 15 章處理共識、第 16 章處理跨節點交易、第 17 章處理網路與儲存層。
閱讀文章 →共識:Raft 與 Paxos
一群節點要對一個值(或一串值)達成一致,即使部分節點當機、網路延遲或分割。正確的共識演算法滿足: FLP 不可能結果(Fischer, Lynch, Paterson 1985):在完全非同步的系統中,只要可能有一個節點當機,就沒有確定性演算法能保證終止。 實務的繞法是假設部分同步(timeout 最終會可靠)並使用隨機化(Raft 的隨機選舉逾時)——演算法永遠保證安全性,活性則在網路「夠好」時成立。
閱讀文章 →分散式交易
代價:正常路徑 2 輪往返、每個節點至少 2 次 fsync(參與者 PREPARE + COMMIT;協調者 COMMIT),鎖的持有時間延長至跨網路的兩個階段。 Presumed abort 最佳化:協調者不記錄 abort 決定,查無記錄即視為 abort,省下 abort 路徑的日誌與 ACK。 唯讀參與者可在 Phase 1 直接回 READ-ONLY 並退出。
閱讀文章 →資料庫網路與分散式儲存
PostgreSQL 的 wire protocol 自 7.4 起為 v3.0,PostgreSQL 18 新增 v3.2(更長的取消金鑰、協商機制;libpq 預設仍以 3.0 連線)。所有訊息(除第一個 startup message)格式一致: 1 byte 訊息型別 + int32 長度(含自身)+ 內容,整數為大端序,字串以 NUL 結尾。
閱讀文章 →資料庫安全
資料庫是攻擊者的終極目標:它存著一切。常見攻擊面包括:暴露在網際網路的連接埠、弱或外洩的密碼、應用程式的 SQL injection、 權限過大的帳號(應用程式用 superuser)、未加密的備份與日誌、內部人員、以及未修補的已知漏洞。 沒有單一機制能擋住全部,縱深防禦讓每一層的失守都被下一層限制損害範圍:
閱讀文章 →動手打造 MiniDB
前 18 章的每個概念——slotted page、latch crabbing、clock sweep、WAL 的兩條規則、可見性判定、Selinger DP——在實作它們之前都只是知識; 實作之後才會變成直覺。MiniDB 的目標不是取代任何資料庫,而是一個約 10–15k 行、你完全理解每一行的系統。 三個原則:正確優先(每個版本都有完整測試)、小步前進(每個版本都是可用的資料庫)、抄最好的設計(命名與架構盡量跟隨 Postgre
閱讀文章 →PostgreSQL 原始碼導覽地圖
本附錄把前面各章的概念對應到 PostgreSQL 18 原始碼樹中的位置。閱讀原始碼最有效的順序是: 先讀該目錄的 README(PostgreSQL 的 README 是一流的設計文件),再讀標頭檔中的結構定義(src/include/),最後才讀 .c。
閱讀文章 →完整學習資源清單
本附錄彙整全書引用與推薦的資源,依類型排列;每章末的「延伸閱讀」則依主題排列。標示 72 者為本教材認為該類別中最值得優先投入的資源。
閱讀文章 →中英術語對照表
本表依英文字母排序,收錄全書出現的核心術語、本教材採用的中文譯名與一句話定義,並標示主要討論的章節。 中文資料庫文獻的譯名並不統一(例如 transaction 有「交易」與「事務」兩種常見譯法),本教材在全書中採用台灣常用的譯法,並在首次出現時附上英文。
閱讀文章 →MongoDB Training Course - Overview
This comprehensive MongoDB training course is designed for students learning NoSQL databases from scratch. The course materials are organized into clear, progressive modules.
閱讀文章 →