Таблица в PostgreSQL - это не один файл. Это несколько параллельных файлов, каждый со своей ролью. Их называют форками (forks). Главный форк хранит строки, остальные - служебные карты, которые ускоряют работу.
Найти главный файл таблицы можно из SQL:
SELECT pg_relation_filepath('flights');-- base/16384/16503
Путь читается так: base/ - каталог обычных баз, 16384 - OID базы,
16503 - relfilenode, имя файла этой таблицы. Конкретные числа у тебя
будут другими: OID назначаются по мере создания объектов. Подробнее про
путь до базы - в cluster-pgdata.
Четыре форка
| Форк | Суффикс файла | Что хранит |
|---|---|---|
| main | нет | сами строки таблицы (или записи индекса) |
| fsm | _fsm | карта свободного места по страницам |
| vm | _vm | карта видимости и заморозки |
| init | _init | пустой шаблон для нежурналируемых таблиц |
Главный форк есть всегда. Остальные появляются по мере надобности.
Сразу после CREATE TABLE на диске только главный файл. Карты _fsm и
_vm создаются позже - обычно при первом VACUUM или когда серверу
понадобится свободное место под вставку. Про эти карты есть отдельные
заметки: free-space-map и visibility-map.
-- сразу после CREATE TABLE: только главный форк
SELECT pg_relation_filepath('t'); -- base/16384/24576 (число своё)-- файлов 24576_fsm и 24576_vm ещё нет
VACUUM t; -- теперь карты появятся
relfilenode - это не OID
У отношения есть OID (внутренний идентификатор в системном каталоге) и
relfilenode (имя файла на диске). Поначалу они совпадают. Но команды,
которые переписывают таблицу целиком - VACUUM FULL, TRUNCATE,
CLUSTER, ALTER TABLE, меняющий тип колонки, - создают новый файл с
новым relfilenode и удаляют старый. OID при этом остаётся прежним.
Поэтому в коде, который должен пережить перезапись, ссылаются на OID, а
не на имя файла. А pg_relation_filepath() всегда показывает актуальный
relfilenode, считывая его из каталога.
Сегменты по гигабайту
Один форк не растёт одним бесконечным файлом. Когда главный форк
переваливает за 1 ГБ, PostgreSQL продолжает в файле relfilenode.1,
затем relfilenode.2 и так далее. Это упрощает жизнь старым файловым
системам с лимитом на размер файла и операциям копирования. Для тебя как
читателя это значит: большая таблица на диске - это пачка файлов
16385, 16385.1, 16385.2, а не один гигантский.
Зачем это знать
Когда видишь в base/16384/ россыпь файлов с суффиксами и номерами, это
не хаос, а форки и сегменты конкретных таблиц. Размер _fsm и _vm
крошечный по сравнению с главным форком, но именно они позволяют вставке
не сканировать таблицу в поисках места, а вакууму - пропускать страницы,
где всё уже видимо.