lesson ── postgres-labs ── ~20 мин ── 4 шагов
Создай две таблицы с одинаковыми колонками в разном порядке и измерь разницу в байтах. Перед запросом предсказывай lp_len каждой по раскладке: где появится заполнитель, а где нет.
интерактивный sandbox
Поднимется контейнер postgreslab/postgres-base с PostgreSQL 17 и psql. В браузере откроется терминал, база lab уже настроена. Каждый шаг проверяется автоматически. Сеть air-gapped, наружу контейнер не ходит.
stack ── PostgreSQL 17 · psql · 1 GB RAM · air-gapped · самоуничтожается через 45 мин простоя
Создай таблицы с одними и теми же колонками, но в разном порядке, и вставь по строке.
CREATE TABLE align_bad (a smallint, b bigint, c smallint);
CREATE TABLE align_good (b bigint, a smallint, c smallint);
INSERT INTO align_bad VALUES (1, 2, 3);
INSERT INTO align_good VALUES (2, 1, 3);
✓ Обе таблицы готовы, по одной строке в каждой.
Предскажи lp_len для align_bad: 24 (заголовок) плюс данные с заполнителем перед bigint. Проверь.
SELECT lp_len FROM heap_page_items(get_raw_page('align_bad', 0));После первого smallint (смещение 2) до bigint нужно добить 6 байт.
✓ 42 байта: 24 заголовок + 18 данных с шестью байтами заполнителя.
Предскажи lp_len для align_good - заполнителя быть не должно, bigint выровнен сразу. Проверь.
SELECT lp_len FROM heap_page_items(get_raw_page('align_good', 0));✓ 36 байт: те же данные без шести байт заполнителя.
Выравнивание записано в pg_type. Узнай его для bigint - буква 'd' означает кратность 8.
SELECT typname, typalign, typlen FROM pg_type WHERE typname = 'int8';
typalign: c=1, s=2, i=4, d=8 байт.
✓ bigint выровнен по 8 байтам (typalign = d) - вот откуда заполнитель.
Один набор колонок в разном порядке дал 42 и 36 байт на строку: разница в шести байтах заполнителя перед bigint. Эвристика - перечислять колонки по убыванию выравнивания, от широких к узким.
команды
SELECT lp_len FROM heap_page_items(get_raw_page('t',0));реальная длина строки на дискеSELECT typname, typalign FROM pg_type WHERE typname='int8';выравнивание типаконцепции