linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Главы
  • How it worksскоро
  • Уроки
  • База знаний
  • Собеседование
home/postgres/kb/Хранение и формат на диске/tuple-header

kb/storage ── Хранение и формат на диске ── intermediate

Заголовок кортежа

Перед данными каждой строки лежит служебный заголовок в 23 байта, выровненный до 24. В нём t_xmin и t_xmax (кто вставил и кто удалил версию), t_ctid (ссылка на себя или на новую версию), t_infomask с флагами и t_hoff - смещение до пользовательских данных. Это поля, на которых стоит весь MVCC.

view as markdownaka: heap-tuple-header, t-hoff

У каждой строки в heap есть заголовок кортежа - фиксированный блок служебных полей перед самими данными. Он занимает 23 байта и выравнивается до 24. В этих байтах закодировано, какая транзакция строку создала, какая удалила, где её следующая версия и как читать данные дальше.

Прочитать заголовки всех строк на странице:

sql
SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask2, t_infomask, t_hoff
FROM heap_page_items(get_raw_page('t', 0));

Поля заголовка

ПолеРазмерСмысл
t_xmin4 байтаxid транзакции, вставившей эту версию
t_xmax4 байтаxid транзакции, удалившей версию (0, если жива)
t_field34 байтаcommand id или служебное поле вакуума
t_ctid6 байтадрес этой или следующей версии: (страница, указатель)
t_infomask22 байтачисло колонок + флаги HOT
t_infomask2 байтабитовые флаги состояния и подсказки фиксации
t_hoff1 байтсмещение до пользовательских данных

xmin, xmax и ctid - сердце версионности

t_xmin и t_xmax определяют время жизни версии строки. Версия видна транзакции, если её xmin уже зафиксирован и попадает в снимок, а xmax ещё нет. Правила видимости подробно разбирает xmin-xmax.

t_ctid обычно указывает на саму строку. Но после UPDATE старая версия начинает указывать на новую: так получается цепочка версий. Поэтому обновление одной строки можно проследить, идя по ctid от версии к версии.

sql
INSERT INTO t VALUES (1, 'a');        -- появилась версия с ctid (0,1)
UPDATE t SET note = 'b' WHERE id = 1; -- старая версия (0,1) теперь ведёт на (0,2)

infomask: флаги и подсказки

t_infomask хранит битовые флаги. Часть из них - подсказки фиксации (hint bits): отметки «xmin точно зафиксирован» и «xmax точно зафиксирован». Их ставит первый прочитавший строку, чтобы следующим не лезть в clog за статусом транзакции. Механику разбирает clog-hint-bits. Другие биты говорят, есть ли в строке NULL-значения и значения переменной длины - это влияет на размер заголовка через t_hoff.

t_hoff и выравнивание

t_hoff - это смещение от начала кортежа до первого пользовательского байта. Без NULL-значений заголовок занимает ровно 24 байта, и t_hoff = 24. Если в строке есть NULL, после заголовка добавляется битовая карта NULL, и t_hoff вырастает. Где именно лягут сами колонки за заголовком, определяет их выравнивание - об этом column-alignment.

§ команды

bash
SELECT lp, t_xmin, t_xmax, t_ctid, t_hoff FROM heap_page_items(get_raw_page('t', 0));

Версионные поля и смещение данных для всех строк страницы 0

bash
SELECT ctid, xmin, xmax, * FROM t;

Системные колонки xmin/xmax/ctid прямо в выдаче таблицы

bash
SELECT t_infomask::bit(16) FROM heap_page_items(get_raw_page('t', 0));

infomask в двоичном виде - видно выставленные флаги и hint bits

§ см. также

  • xmin-xmaxxmin, xmax и правила видимостиУ каждой версии строки два транзакционных штампа: xmin (кто вставил) и xmax (кто пометил устаревшей, 0 - если жива). Версия видна транзакции, если её xmin уже зафиксирован и попадает в снимок, а xmax либо пуст, либо ещё не зафиксирован, либо не виден снимку. По этим двум числам строится вся видимость.
  • line-pointersLine pointers и lp_flagsУказатель строки (line pointer) - это 4 байта в начале страницы: смещение до кортежа, его длина и флаг состояния. Флаг lp_flags бывает четырёх видов: unused, normal, redirect, dead. Внешний адрес строки (ctid) - это номер указателя, а не позиция в байтах, поэтому строка может двигаться внутри страницы, не меняя адреса.
  • column-alignmentВыравнивание и порядок колонокВнутри строки колонки лежат с выравниванием: bigint и timestamp хотят начинаться с адреса, кратного 8, int - кратного 4. Между колонками PostgreSQL вставляет байты-заполнители (padding). Поэтому порядок колонок влияет на размер строки. Если расставить колонки от широких к узким, заполнителей становится меньше и строка занимает меньше места.
  • clog-hint-bitsclog и подсказки фиксации (hint bits)Зафиксирована транзакция или откатилась, хранит clog (каталог pg_xact) - всего два бита на транзакцию. Чтобы не дёргать clog при каждом чтении строки, результат проверки кэшируется в самой строке подсказками фиксации в t_infomask. Первый прочитавший строку ставит подсказку - и тем самым пачкает страницу, даже если это был обычный SELECT.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки