Books

Best Database Internals Books: Storage Engines, MVCC and WAL

This post contains affiliate links. If you buy through them, we may earn a small commission at no extra cost to you. Learn more.

A one-row INSERT wrote three WAL records and 272 bytes on PostgreSQL 18.6 (benchmarked November 2026 on Ubuntu 24.04). The records were a 164-byte heap insert, a 64-byte B-tree leaf insert and a 34-byte commit. Most of the database internals books below explain why those three records exist and why they reach disk before the commit returns. The two exceptions are flagged in their own sections. They differ in depth, example engine and the age of their hardware assumptions.

Original content from computingforgeeks.com - post 182519

We ranked eight books first by how many of six mechanisms each one covers in its own chapter, then by how current and how practical the rest are. The six are page layout, B+tree indexes, MVCC, write-ahead logging and recovery, the buffer manager, and isolation. Editions and prices came from the Amazon US catalog on November 1, 2026, and chapter claims from the publisher table of contents. We then measured the same six mechanisms on PostgreSQL 18 and MySQL 8.4, so each pick reads against real output.

Quick picks by what you are building

Most readers need one storage book and one reference, not all eight. Match the line to the work in front of you and start there:

We found no book from an established publisher sold new on Amazon US that is mainly about PostgreSQL internals (the 2025 Apress title Mastering PostgreSQL Administration carries the word in its subtitle but is an administration and migration guide), and the only English MySQL internals title from one that is still sold new dates from 2007. For those two engines the strongest material is free, and it is listed after the lab section.

Compare the eight database internals books

Each row shows the edition we link, the level of the system the book works at, the language of any code, and its age. Treat the Published column as a hardware column as well. A 1992 or 2002 book assumes spinning disks and lock-based concurrency. It still explains the ideas well, but not the defaults a current engine ships with.

BookWorks atCodePagesPublishedPrice, Nov 1 2026 (sale to list)
Database InternalsStorage engine and distributed layerPseudocode370Nov 2019about $36 to $66
Database System Concepts, 7th Ed.Whole DBMS, textbookPseudocode, SQL1,376Apr 2019about $80 to $109
Database Design and Implementation, 2nd Ed.Whole DBMS, built in codeJava458Feb 2020about $44 to $65
Build Your Own Database From Scratch in GoKV store up to a small SQL layerGo104 as listedJun 2024about $33
Designing Data-Intensive Applications, 2nd Ed.Data systems surveyNone670Mar 2026about $48 to $70
Transaction ProcessingLogging, locking, recoveryC fragments1,128Sep 1992about $73
Understanding MySQL InternalsMySQL server sourceC++ source walk254May 2007about $15 to $50
Database Management Systems, 3rd Ed.Whole DBMS, textbookPseudocode, SQL1,104Aug 2002about $177 to $285

The eight books add up to 5,464 printed pages by the catalog counts. The two textbooks alone account for 2,480 of them, so nobody reads this shelf end to end. Four of the eight listed as scarce on November 1, 2026: Database System Concepts, Transaction Processing, Understanding MySQL Internals and Database Management Systems. Check stock on the listing before you plan a reading order around one of them.

How the books were ranked

A book guide has no throughput number, so we scored what can be counted. Each candidate went through four checks before it was ranked:

  • Coverage: a dedicated chapter or numbered section for each of the six mechanisms, read from the publisher or author table of contents, never from the Amazon blurb.
  • Edition and format: the Amazon Creators API returned binding, pages and date for every ASIN, and the cover shown matches the edition linked.
  • Stock: every pick was sold new on Amazon US on November 1, 2026, with no used-only buy box in the catalog audit.
  • Price against age: a 2002 textbook at $177 drops below a 2019 textbook that teaches the same material at $80.

We did not read every pick cover to cover for this guide. The verdicts rest on each table of contents, the publisher description and the companion code where one exists. They also rest on how well the chapters line up with what the two engines did in the lab, because a chapter that predicts the output is worth more than one that only names the idea.

BookPage layoutB+treeMVCCWAL and recoveryBuffer managerIsolation, locking
Database Internalsch3ch2, ch4ch5ch5 (ARIES)ch5ch5
Database System Conceptsch1314.318.7, 18.8ch19 (ARIES 19.9)13.5ch17, ch18
Database Design and Implementationch3, ch6ch12No (lock-based)ch5ch4, ch14ch5
Build Your Own Database in Goch7 (free list)ch3 to ch5NoCopy-on-write, ch3, ch6Noch11, ch12
Designing Data-Intensive ApplicationsNoch4ch8Brief, ch4Noch8
Transaction Processingch14ch15Noch9 to ch11ch13ch7, ch8
Understanding MySQL InternalsNoNoNoNoNoch8, ch11
Database Management Systemsch9ch10Not a focusch18ch9ch16, ch17

Two books fill all six columns with their own sections, and both rank at the top. Below them, coverage alone does not set the order. The two code-first books come next because they show how a mechanism is built, not only why it exists. DDIA follows as the only 2026 title, then the older references: Transaction Processing fills five columns but predates MVCC, SSDs and LSM trees as mainstream designs, so it sits below newer books with fewer cells. Understanding MySQL Internals fills one column and stays on the list because it is the only print book that walks the MySQL server code. Database Management Systems ranks last on price.

1. Database Internals

Alex Petrov wrote the best single book on how storage engines and the distributed layer above them are built, and it is the first one to buy for this subject.

Database Internals by Alex Petrov book cover, O'Reilly first edition
Database Internals, 1st Edition by Alex Petrov. Image: O’Reilly Media.

O’Reilly published it in November 2019 at 370 pages, and Part I is the storage engine half. Chapter 2 covers B-tree basics and chapter 3 file formats with slotted pages and checksums. Chapter 4 handles the implementation details: splits, merges, overflow pages and bulk loading. Chapter 5 is the densest part of the book, because it puts buffer management, page replacement, ARIES recovery, steal and force policies, MVCC and isolation levels into one chapter.

The slotted-page chapter maps directly onto the PostgreSQL output later in this guide. There, heap_page_items lists line pointers that point at tuples inside an 8 KB page. Chapter 6 covers B-tree variants such as copy-on-write trees in LMDB, lazy B-trees in WiredTiger and Bw-trees. Chapter 7 gives LSM trees, SSTables, Bloom filters and the RUM conjecture their own treatment. Part II moves up to failure detection, leader election and replication. It ends with distributed transactions (2PC, 3PC, Calvin, Spanner, Percolator) and consensus with Paxos, Raft and ZAB.

Pass on it if query planning is your topic, because the book has no query processing or optimizer chapter. It also uses no single engine as a running example, so PostgreSQL and InnoDB specifics come from the free material below. We found no second edition listed on Amazon or on the author site in November 2026. The paperback sold new for about $36 against a $65.99 list price on November 1, 2026. Check the current price before you order.

2. Database System Concepts, 7th Edition

Silberschatz, Korth and Sudarshan wrote the reference that the Carnegie Mellon database systems course still assigns, and it is the pick for anyone working through CMU-style storage engine material.

Database System Concepts 7th Edition International Student Edition by Silberschatz, Korth and Sudarshan book cover
Database System Concepts, 7th Edition (International Student Edition) by Silberschatz, Korth and Sudarshan. Image: McGraw Hill.

The CMU 15-445/645 Fall 2026 syllabus lists “DB System Concepts (7th Ed.)” as its textbook. The course projects build pieces of the BusTub database in C++17. The book covers storage in chapter 13, where 13.5 is the database buffer. B+-tree index files are 14.3 and write-optimized structures such as LSM trees are 14.8. Query processing and optimization take chapters 15 and 16. Multiversion schemes and snapshot isolation sit in 18.7 and 18.8, and ARIES is section 19.9.

We link the paperback that Amazon US had in stock on November 1, 2026. Its cover carries a banner saying the International Student Edition is for use outside the U.S. The US hardcover (ASIN 0078022150) was out of stock that day, so expect this printing if you order through the link. Both list 1,376 pages for the 2019 seventh edition, and we found no eighth edition announced.

Look elsewhere if you want one real engine dissected. The chapters teach in pseudocode and general terms rather than through PostgreSQL or InnoDB. At 1,376 pages it is also a reference to read in the order a course sets, not front to back. The paperback sold for about $80 against a $108.99 list price and listed as scarce, so check the current price and stock.

3. Database Design and Implementation, 2nd Edition

Edward Sciore teaches the internals by building a complete teaching database, SimpleDB, one component per chapter, which suits a reader who learns by reading working code.

Database Design and Implementation Second Edition by Edward Sciore book cover
Database Design and Implementation, Second Edition by Edward Sciore. Image: Springer.

Springer published the second edition in February 2020 at 458 pages in its Data-Centric Systems and Applications series. The chapter order follows the layers of an engine from the disk up. Chapter 3 is disk and file management, chapter 4 memory management, chapter 5 transaction management and chapter 6 record management. Metadata, query processing, parsing and planning come next. Indexing arrives in chapter 12, effective buffer utilization in chapter 14 and query optimization in chapter 15.

The code is Java, and Springer states that the book assumes the reader is comfortable with basic Java. Amazon lists the edition as “1st”, but the Springer page and the cover both say Second Edition. Concurrency in SimpleDB is lock-based, so the MVCC behavior in the lab below is something to read about in Petrov or the CMU textbook rather than trace in this code.

Readers who do not know Java, or who want LSM trees and distributed storage, should choose another pick, since neither is the focus here. The paperback sold new for about $44 against a $64.99 list price on November 1, 2026. Check the current price before buying.

4. Build Your Own Database From Scratch in Go

James Smith wrote the shortest path from an empty file to a working B+tree, a durable key-value store and a small SQL layer, all in Go.

Build Your Own Database From Scratch in Go 2nd Edition by James Smith book cover
Build Your Own Database From Scratch in Go, 2nd Edition by James Smith. Image: build-your-own.org.

Part I builds a key-value store. Chapter 3 covers B-trees and crash recovery, chapters 4 and 5 B+tree insertion and deletion, chapter 6 an append-only copy-on-write store and chapter 7 a free list for page reuse. Part II turns the store into a relational layer with rows and columns, secondary indexes and atomic transactions. It finishes with concurrent readers and writers and a SQL-like parser. The cover promises the whole path in 3,000 lines of code, and Part I is free to read on the author site before you buy.

Durability here comes from copy-on-write pages rather than a write-ahead log. That is the LMDB design family Petrov covers in chapter 6. It makes the book a good contrast to the PostgreSQL WAL records measured below, but not a guide to them. The book is independently published on a 979 ISBN, and the author site links the same Amazon listing. The catalog page count of 104 looks low against the content, so treat that number as a listing artifact.

WAL-based recovery, LSM trees and distributed storage are all absent, so this is the wrong book for any of those three. The paperback sold new for about $33 on November 1, 2026. Check the current price on the listing.

5. Designing Data-Intensive Applications, 2nd Edition

Martin Kleppmann and Chris Riccomini cover the layer above the storage engine: replication, sharding, transactions and consensus, with one chapter on the engine itself.

Designing Data-Intensive Applications 2nd Edition by Martin Kleppmann and Chris Riccomini book cover
Designing Data-Intensive Applications, 2nd Edition by Martin Kleppmann and Chris Riccomini. Image: O’Reilly Media.

O’Reilly released the second edition in March 2026 at 670 pages. Chapter 4, Storage and Retrieval, covers storage and indexing for OLTP, analytics storage, and multidimensional and full-text indexes. Chapters 6 and 7 cover replication and sharding. Chapter 8 runs from weak isolation levels to serializability and distributed transactions, and chapter 10 covers consistency and consensus.

It ranks fifth here only because it is a survey. There is no buffer manager chapter, no recovery algorithm and no code. So it explains why an engine picks a B-tree or an LSM tree without showing how either is built. It also ties this shelf to the rest of the site. It leads our system design books list and sits in the data modeling and database design books guide, so one copy serves all three topics.

Engine developers should not make it their only internals book, since it explains choices rather than code. The paperback sold new for about $48 against a $69.99 list price on November 1, 2026. Check the current price before you order.

6. Transaction Processing: Concepts and Techniques

Jim Gray and Andreas Reuter wrote the long-form reference on logging, locking and recovery, and it remains the deepest single treatment of those three subjects on this list.

Transaction Processing Concepts and Techniques by Jim Gray and Andreas Reuter book cover
Transaction Processing: Concepts and Techniques by Jim Gray and Andreas Reuter. Image: Morgan Kaufmann.

Morgan Kaufmann published the 1,128-page hardcover in September 1992. Chapter 7 covers isolation concepts including predicate and granular locks, and chapter 8 the lock manager and latches. Chapter 9 is the log manager with group commit. Chapter 10 covers physiological logging, write-ahead logging, compensation log records and two-phase commit, and chapter 11 fuzzy checkpoints and restart. File and buffer management follow in chapter 13 and the mapping of tuples into pages in chapter 14. B-tree access paths with their synchronization, recovery and key-range locking come in chapter 15.

Physiological logging is visible in the lab output below. Each PostgreSQL WAL record names a relation, a block and an offset inside that block. That is the split this book describes: physical down to the page, logical within it. Group commit is what keeps the MySQL default innodb_flush_log_at_trx_commit=1 affordable, since many commits share one log flush. The code fragments are in C.

MVCC, SSD-aware storage and LSM trees all became mainstream after it, so leave it on the shelf if those are your topics. The hardcover sold new for about $73 on November 1, 2026 and listed as scarce. Check the current price and stock before you order.

7. Understanding MySQL Internals

Sasha Pachev wrote the only English print book that walks the MySQL server source, from the client protocol down to the storage engine interface.

Understanding MySQL Internals by Sasha Pachev book cover, O'Reilly
Understanding MySQL Internals by Sasha Pachev. Image: O’Reilly Media.

O’Reilly published it in May 2007 at 254 pages. Chapter 3 covers core classes such as THD, TABLE and Field, and chapter 6 thread-based request handling. Chapter 7 is the storage engine interface built around the handler class, and chapter 8 concurrent access and locking. Chapter 9 covers the parser and optimizer, and chapters 11 and 12 transactions and replication. InnoDB gets section 10.2, among MyISAM, Merge, NDB, Archive and Federated, plus section 8.1.3 on its locking.

The age shows. The book describes the MySQL 5.0 and 5.1 era, and it lacks the InnoDB detail you would want for the clustered index, buffer pool, redo and undo logs. We searched the catalog for a newer English print book on InnoDB internals and found none. The one candidate was a self-published Kindle-only title we did not vet. For operations on a current server, our MySQL and MariaDB books guide covers the 8.4-era titles.

Buy it only if you plan to read or modify the MySQL server code itself. The paperback sold new for about $15 against a $49.99 list price on November 1, 2026. Only one copy was left at that price, so check stock before you order.

8. Database Management Systems, 3rd Edition

Raghu Ramakrishnan and Johannes Gehrke wrote the other classic systems textbook, known as the Cow Book, and it still teaches storage, indexing and recovery clearly.

Database Management Systems 3rd Edition by Raghu Ramakrishnan and Johannes Gehrke book cover
Database Management Systems, 3rd Edition by Ramakrishnan and Gehrke. Image: McGraw-Hill.

McGraw-Hill published the third edition in August 2002 at 1,104 pages. Chapter 9 covers data storage, chapter 10 tree indexes and chapter 11 hash indexes. Chapter 13 is external sorting, chapter 14 relational operators and chapter 15 a typical relational optimizer. Transactions, concurrency control and recovery take chapters 16 to 18. The authors keep open-access chapter slides on the book site at the University of Wisconsin.

It ranks last on price, not on quality. The hardcover sold new for about $177 against a $284.67 list price on November 1, 2026 and listed as scarce. The 2019 Silberschatz text covers the same ground for less than half that, and adds sections on snapshot isolation and write-optimized indexes. Buy it only if a course requires it, and use the free slides otherwise.

What the books describe, measured on PostgreSQL 18 and MySQL 8.4

Every mechanism in the coverage table leaves traces you can read on a running server. We loaded the same one-million-row table into both engines on one Ubuntu 24.04 VM with 2 vCPUs and 4 GB of RAM. Both ran from the official Docker images with default settings, and this is what each engine reported:

MeasurementPostgreSQL 18.6MySQL 8.4.13 (InnoDB)Where the books cover it
Page size8,192 bytes16,384 bytesPetrov ch3, Silberschatz ch13
Primary key B+tree, 1M rows3 levels, 2,745 pages8,476 leaf pages of 8,492Petrov ch2 and ch4, Silberschatz 14.3
Rows per leaf page367 index entriesabout 118 full rowsClustered vs secondary index sections
Table storage135 MB heap plus 21 MB index139,132,928 bytes, index_length 0Silberschatz ch13 and ch14
Log bytes for 100,000 inserted rows23,478,456 WAL bytes16,734,720 redo bytesGray and Reuter ch9 and ch10, Petrov ch5
Default isolationread committedREPEATABLE-READSilberschatz ch17 and ch18, DDIA ch8

The steps below reproduce every row on any Linux host that runs Docker. The password StrongPass123 is a lab value, so replace it on anything that is not a throwaway VM. Readers who prefer a native PostgreSQL install can follow our PostgreSQL on Debian guide and run the same SQL there.

Start PostgreSQL 18 and MySQL 8.4 in containers

Ubuntu 24.04 ships Docker as the docker.io package, which installed Docker 29.1.3 on the test VM:

sudo apt-get update && sudo apt-get install -y docker.io

Start one container per engine. MySQL initialises its data directory on the first start with a temporary server that also logs “ready for connections”. Wait until sudo docker logs mysql84 shows that line with port: 3306 before you query it:

sudo docker run -d --name pg18 -e POSTGRES_PASSWORD=StrongPass123 postgres:18
sudo docker run -d --name mysql84 -e MYSQL_ROOT_PASSWORD=StrongPass123 mysql:8.4

Confirm the versions and read the page size of each engine. The page is the unit every internals book builds on, and the two engines picked different sizes:

sudo docker exec pg18 psql -U postgres -c 'SELECT version();'
sudo docker exec mysql84 mysql -uroot -pStrongPass123 -e 'SELECT VERSION();'
sudo docker exec pg18 psql -U postgres -c 'SHOW block_size;'
sudo docker exec mysql84 mysql -uroot -pStrongPass123 -e 'SELECT @@innodb_page_size;'

PostgreSQL reported 18.6 with 8,192-byte blocks, and MySQL reported 8.4.13 with 16,384-byte InnoDB pages:

PostgreSQL 18.6 block_size 8192 and MySQL 8.4.13 innodb_page_size 16384 in a terminal

Both sizes are compile-time or initialisation-time choices, not settings you change on a running server. A larger page holds more entries per node before it splits, which matters for the B+tree numbers next.

Measure B+tree height and fanout for one million rows

Create a database and a table with a bigint primary key and a 100-byte payload, then load one million rows with generate_series:

sudo docker exec pg18 psql -U postgres -c 'CREATE DATABASE bench;'
sudo docker exec pg18 psql -U postgres -d bench -c 'CREATE TABLE t (id bigint PRIMARY KEY, payload char(100));' -c "INSERT INTO t SELECT g, 'x' FROM generate_series(1,1000000) g;" -c 'VACUUM ANALYZE t;'

The pageinspect extension reads index and heap pages directly. bt_metap returns the level of the root, and bt_page_stats describes one page, here block 1, which is a leaf:

sudo docker exec pg18 psql -U postgres -d bench -c 'CREATE EXTENSION pageinspect;' -c "SELECT level, root FROM bt_metap('t_pkey');" -c "SELECT pg_size_pretty(pg_relation_size('t')) AS heap, pg_relation_size('t_pkey')/8192 AS index_pages;"
sudo docker exec pg18 psql -U postgres -d bench -c "SELECT live_items, avg_item_size, free_size, type FROM bt_page_stats('t_pkey', 1);"

The root sits at level 2, so the index has three levels: root, one internal level and the leaves:

pageinspect bt_metap showing a level 2 PostgreSQL B-tree with 2745 index pages for one million rows

Read the leaf numbers against the page size. A leaf held 367 entries of 16 bytes each (an 8-byte key plus an 8-byte index tuple header that carries the heap pointer), and it still had 808 bytes free because PostgreSQL B-tree leaves default to a fill factor of 90 when the index is built and when keys arrive in ascending order, as they did here. Three levels for a million keys is what Petrov and Silberschatz predict for a fanout in the hundreds. The 135 MB heap sits outside the index, so a lookup that needs the payload reads one more page to fetch the row.

InnoDB stores the same table differently. Load the identical rows with a recursive CTE, then read the persistent index statistics:

sudo docker exec mysql84 mysql -uroot -pStrongPass123 -e 'CREATE DATABASE bench; CREATE TABLE bench.t (id bigint PRIMARY KEY, payload char(100));'
sudo docker exec mysql84 mysql -uroot -pStrongPass123 bench -e "SET SESSION cte_max_recursion_depth=1000000; INSERT INTO t WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<1000000) SELECT n, 'x' FROM s; ANALYZE TABLE t; SELECT stat_name, stat_value FROM mysql.innodb_index_stats WHERE database_name='bench' AND table_name='t';"
sudo docker exec mysql84 mysql -uroot -pStrongPass123 bench -e "SELECT data_length, index_length, table_rows FROM information_schema.TABLES WHERE table_schema='bench' AND table_name='t';"

The innodb_index_stats table reported 8,476 leaf pages out of 8,492 for the PRIMARY index, and index_length came back as 0:

InnoDB innodb_index_stats showing 8476 leaf pages and index_length 0 for a clustered primary key on MySQL 8.4

That zero is the clustered index made visible. InnoDB keeps the full rows in the leaves of the primary key B+tree, so the table and its primary index are one structure. Its 8,492 pages of 16 KB come to exactly the 139,132,928 bytes reported as data_length. About 118 rows fit per leaf, against 367 bare keys per PostgreSQL leaf. Only 16 allocated pages sit outside the leaf level, which is consistent with a three-level tree. The table_rows value of 991,692 is a sampled estimate for a table that holds exactly one million rows, so do not trust that column for exact counts in monitoring.

Watch MVCC keep three versions of one row

PostgreSQL implements MVCC by writing a new tuple version on every update and marking the old one with the deleting transaction ID. Insert one row and update it twice:

sudo docker exec pg18 psql -U postgres -d bench -c 'CREATE TABLE mv (id int PRIMARY KEY, v int);' -c 'INSERT INTO mv VALUES (1,10);' -c 'UPDATE mv SET v=20 WHERE id=1;' -c 'UPDATE mv SET v=30 WHERE id=1;'
sudo docker exec pg18 psql -U postgres -d bench -c "SELECT lp, lp_flags, t_xmin, t_xmax, t_ctid FROM heap_page_items(get_raw_page('mv', 0));"

The heap page holds three physical tuples for one logical row, chained by t_ctid:

heap_page_items showing three MVCC tuple versions with xmin and xmax after two updates in PostgreSQL 18

Transaction 782 created the first version and 783 ended it. Transaction 783 created the second and 784 ended it. The third version has t_xmax 0, so it is the live one. A snapshot taken before transaction 783 committed would still see v=10, which is snapshot isolation in three rows of output. InnoDB solves the same problem with undo logs instead. It updates the clustered row in place and rebuilds old versions on demand, the contrast Silberschatz covers in 18.7 and 18.8.

Run VACUUM and read the same page again:

sudo docker exec pg18 psql -U postgres -d bench -c 'VACUUM mv;' -c "SELECT lp, lp_flags, lp_off, t_xmin, t_xmax, t_ctid FROM heap_page_items(get_raw_page('mv', 0));" -c 'SELECT xmin, xmax, * FROM mv;'

Line pointer 1 now has flag 2 (a redirect to slot 3), slot 2 is unused, and only the live tuple remains:

PostgreSQL VACUUM turning a HOT chain into a redirect line pointer and an unused slot

Both updates touched only the non-indexed column, so PostgreSQL used heap-only tuples and never wrote new index entries. The index still points at line pointer 1, which is why VACUUM keeps that slot as a redirect instead of freeing it. The slotted-page design in Petrov chapter 3 is what makes that indirection cheap.

Read the WAL records of a single INSERT

Take the current WAL position, insert one row, take the position again, and decode everything between the two with pg_waldump. The data directory in the official image is /var/lib/postgresql/18/docker. The LSN values in the last command are from our run, so use the ones your server prints. Our run did this step after the 100,000-row test below and after an earlier insert of id 1000001, so your heap block number will be lower; any unused id works:

sudo docker exec pg18 psql -U postgres -d bench -tAc 'SELECT pg_current_wal_lsn();'
sudo docker exec pg18 psql -U postgres -d bench -c 'INSERT INTO t VALUES (1000002, 1);'
sudo docker exec pg18 psql -U postgres -d bench -tAc 'SELECT pg_current_wal_lsn();'
sudo docker exec pg18 pg_waldump -p /var/lib/postgresql/18/docker/pg_wal -s 0/23859A70 -e 0/23859B80

Three records came out, all from transaction 788:

pg_waldump output for a one-row INSERT showing Heap INSERT, Btree INSERT_LEAF and Transaction COMMIT records

The heap insert is 164 bytes and names relation 16447, block 20689 and offset 40. The B-tree record is 64 bytes for block 2744 of the index, and the commit is 34 bytes. The LSN moved by 272 bytes, 10 more than the three record lengths, which is alignment padding. No record carried a full-page image here. The first change to a page after a checkpoint would carry one, because full_page_writes is on by default. That is the torn-page protection that Gray and Reuter and Petrov chapter 5 explain.

Compare WAL bytes against InnoDB redo bytes

Scale the same test to 100,000 rows in one statement on each engine and count the log bytes written. PostgreSQL reports the LSN difference directly:

printf '%s\n' "SELECT pg_current_wal_lsn() AS b \gset" "INSERT INTO t SELECT g, 'x' FROM generate_series(2000001,2100000) g;" "SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), :'b') AS wal_bytes;" | sudo docker exec -i pg18 psql -U postgres -d bench

InnoDB exposes the bytes written to its redo log as the Innodb_os_log_written status counter, so read it before and after the insert:

sudo docker exec mysql84 mysql -uroot -pStrongPass123 bench -e "SET SESSION cte_max_recursion_depth=100000; SELECT VARIABLE_VALUE INTO @a FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_os_log_written'; INSERT INTO t WITH RECURSIVE s(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM s WHERE n<100000) SELECT n+2000000, 'x' FROM s; SELECT (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_os_log_written')-@a AS redo_bytes;"

We ran each twice with a fresh ID range, and the second runs used 3000001 onward:

PostgreSQL WAL bytes against InnoDB redo bytes for a 100,000 row insert on PostgreSQL 18 and MySQL 8.4

PostgreSQL wrote 23,478,456 and 23,486,656 WAL bytes, about 235 bytes per row. InnoDB wrote 16,734,720 and 16,777,728 redo bytes, about 167 to 168 bytes per row. The ratio held at 1.40 on both runs. The single-row dump explains most of the PostgreSQL figure, because a separate heap record and index record (164 plus 64 bytes) are logged for each row. InnoDB logs the clustered-leaf change plus a small undo record, with no separate index record, since the row lives inside the index. Its counter also counts whole 512-byte log blocks, so it rounds up slightly. Neither number includes the InnoDB doublewrite buffer, a separate write path that runs when dirty pages are flushed. Treat this as log volume, not total I/O.

Check the defaults the books argue about

Isolation level, logging and cache defaults are where the textbook discussion meets the shipped configuration. Read them on both servers:

sudo docker exec pg18 psql -U postgres -c 'SHOW default_transaction_isolation;' -c 'SHOW full_page_writes;' -c 'SHOW shared_buffers;' -c 'SHOW wal_level;'
sudo docker exec mysql84 mysql -uroot -pStrongPass123 -e 'SELECT @@transaction_isolation, @@innodb_buffer_pool_size, @@innodb_redo_log_capacity, @@innodb_doublewrite, @@innodb_flush_log_at_trx_commit;'

The two engines disagree on the default isolation level:

Default isolation level and logging settings on PostgreSQL 18 and MySQL 8.4

PostgreSQL defaults to read committed and InnoDB to REPEATABLE-READ. The same application can therefore see different anomalies on the two engines without a single configuration change, the gap DDIA chapter 8 discusses under weak isolation levels. Both start with 128 MB of page cache (shared_buffers and a 134,217,728-byte buffer pool), and InnoDB caps redo at 100 MB. Both protect against torn pages, PostgreSQL with full-page writes and InnoDB with the doublewrite buffer. A tuning book that predates these defaults describes the reasoning correctly but the starting point wrongly.

Free PostgreSQL and InnoDB internals material

Engine-specific internals are where the free material beats anything in print. These five sources cover what the eight books leave out, and every link answered on November 1, 2026:

  • PostgreSQL 14 Internals by Egor Rogov: a free PDF from Postgres Professional in five parts (isolation and MVCC, buffer cache and WAL, locks, query execution, index types). Its print edition is sold through Lulu, not Amazon US.
  • The Internals of PostgreSQL by Hironobu Suzuki: a free online book with chapters on concurrency control, the buffer manager and WAL.
  • CMU 15-445/645: the course site with lecture schedule and BusTub projects, read alongside Database System Concepts.
  • Readings in Database Systems (the Red Book), 5th edition: free at redbook.io, with commentary on the papers behind each design.
  • Build Your Own Database, Part I: the free online half of pick 4, enough to decide whether the print book is worth buying.

For PostgreSQL work, Rogov plus Suzuki covers MVCC, VACUUM and WAL in more engine detail than any book on the list. Our PostgreSQL books guide handles administration and query tuning. We found nothing comparable for InnoDB, so the MySQL reference manual chapters on the InnoDB storage engine remain the primary source there.

Reading order by the engine you work on

The lab numbers suggest the order. Every result above traced back to page layout, the B+tree and the log first, and to isolation second, so start with the book that explains those three and add the engine material after it:

  1. PostgreSQL: Database Internals, then the Rogov PDF, then Suzuki for WAL and the buffer manager.
  2. MySQL and InnoDB: Database Internals, then the InnoDB chapters of the MySQL manual, then Understanding MySQL Internals if you touch the server code.
  3. Your own engine: Build Your Own Database in Go or Sciore for a working base, then Petrov chapter 5 and Gray and Reuter for recovery.
  4. A course: Database System Concepts with the CMU 15-445 lectures, and Petrov for the LSM and distributed chapters the course moves through quickly.

Every engine on this list leans on the operating system for buffering and I/O, so pair this shelf with our operating systems books if that layer is new to you. Re-run the measurements on your own version before quoting them. WAL and redo volumes move with page fill, checkpoint timing and engine release.

Keep reading

Best Machine Learning Books (2026): Textbooks, Python, Free PDFs AI Best Machine Learning Books (2026): Textbooks, Python, Free PDFs Best C++ and C Programming Books for 2026: Beginner to Advanced Books Best C++ and C Programming Books for 2026: Beginner to Advanced Best System Design Books for Interviews and Architecture in 2026 Books Best System Design Books for Interviews and Architecture in 2026 Best OpenShift Books for Admins and EX280 Candidates Books Best OpenShift Books for Admins and EX280 Candidates Best API Design Books: REST, gRPC and GraphQL Books Best API Design Books: REST, gRPC and GraphQL Best SIEM Books: Wazuh, Splunk and Elastic for SOC Teams Books Best SIEM Books: Wazuh, Splunk and Elastic for SOC Teams

Leave a Comment

Press ESC to close