Lesson 5 · Internals & data structures
Storage: pages, heap & tuples
What a table actually is on disk — and why "one row = one tuple" is a lie.
Your win: explain how Postgres physically stores a table's rows, so MVCC, indexes, and VACUUM (the rest of this part) all have somewhere to stand.
A table is a file of 8 KB pages
Physically, a table (the heap) is a sequence of fixed-size pages — 8 KB each.1 The page is the unit of disk I/O and of the in-memory buffer cache: Postgres always reads and writes whole pages, never a single row.
Item pointers (line pointers) grow down from the top; tuples
grow up from the bottom; free space sits between. A tuple's physical address is its
ctid = (page number, item pointer).
A tuple is a row version
emails table is exactly this: a heap of 8 KB pages, each holding many
email tuples. The subject, status, and resource_path
live inline in the tuple; a large content jsonb may be moved out of the page
(Lesson 7, TOAST). Every soft-delete UPDATE will add a new tuple
for the same email_id (Lesson 6).
The Internals of PostgreSQL — heap file & tuple structure
Diagram-rich walkthrough of page layout and tuples; pair with the official page-layout reference for exact bytes.
→ interdb.jp/pg — heap table layout
→ postgresql.org/docs — Database Page Layout
Check yourself (from memory)
Q1. A Postgres table is physically stored as…
Q2. Within a page, tuples are…
ctid.
Q3. One logical row can correspond to…
ctid = (page number, item pointer). Crucially, one
logical row can have multiple tuple versions on disk — the basis of
MVCC.SELECT ctid, * FROM emails, or the
pageinspect extension? Ask me.
1. PostgreSQL — Database Page Layout; The Internals of PostgreSQL.