Документация по PostgreSQL 9.4.1 | |||
---|---|---|---|
Пред. | Уровень выше | Глава 59. Физическое хранение базы данных | След. |
59.6. Компоновка страницы базы данных
В данном разделе рассматривается формат страницы, используемый в таблицах и индексах PostgreSQL.[1] Последовательности и таблицы TOAST форматируются как обычные таблицы.
В дальнейшем подразумевается, что байт содержит 8 бит. В дополнение, термин элемент относится к индивидуальному значению данных, которое хранится на странице. В таблице элемент — это строка; в индексе — элемент индекса.
Каждая таблица и индекс хранятся как массив страниц фиксированного размера (обычно 8 kB, хотя можно выбрать другой размер страницы при компиляции сервера). В таблице все страницы логически эквивалентны, поэтому конкретный элемент (строка) может храниться на любой странице. В индексах первая страница обычно резервируется как метастраница, хранящая контрольную информацию, а внутри индекса могут быть разные типы страниц, в зависимости от метода доступа индекса.
Таблица 59-2 показывает общую компоновку страницы. Каждая страница имеет пять частей.
Таблица 59-2. Общая компоновка страницы
Элемент | Описание |
---|---|
Данные заголовка страницы | Длина - 24 байта. Содержит общую информацию о странице, включая указатели свободного пространства. |
Данные идентификаторов элементов | Массив пар (смещение, длина), указывающих на фактические элементы. Для каждого элемента выделяется 4 байта. |
Свободное пространство | Незанятое пространство. Новые указатели элементов размещаются с начала этой области, сами новые элементы — с конца. |
Элементы | Сами элементы данных как таковые. |
Специальное пространство | Специфические данные метода доступа. Для различных методов хранятся различные данные. Для обычных таблиц таких данных нет. |
Первые 24 байта каждой страницы состоят из заголовка страницы (данные заголовка страницы). Формат заголовка детализирован в Таблице 59-3. Первые два поля отслеживают последнюю запись WAL, связанную с этой страницей. Затем идёт двухбайтовое поле, содержащее биты флагов. За ним следует три двухбайтовых целочисленных поля (pd_lower, pd_upper и pd_special). Эти поля содержат смещения от начала страницы до начала незанятого пространства, до конца незанятого пространства и до начала специального пространства. Следующие 2 байта заголовка страницы, pd_pagesize_version, хранят как размер страницы, так и индикатор версии. Начиная с PostgreSQL 8.3, используется версия 4; PostgreSQL 8.1 и 8.2 использовали версию 3; PostgreSQL 8.0 — версию 2; PostgreSQL 7.3 и 7.4 — версию 1; в более ранних выпусках использовалась версия 0. (Основная компоновка страницы и формат заголовка остались прежними в большинстве этих версий, а компоновка заголовков строк таблицы изменилась.) Размер страницы присутствует, в основном, для осуществления сквозного контроля, так как при установке поддерживается не более одного размера страницы. Последнее поле является подсказкой, которая говорит о том, будет ли очистка страницы являться эффективной: оно отслеживает самый старый идентификатор XMAX на странице, перед которым производилась очистка.
Таблица 59-3. Данные заголовка страницы (PageHeaderData)
Поле | Тип | Длина | Описание |
---|---|---|---|
pd_lsn | XLogRecPtr | 8 байт | LSN: Следующий байт после последнего байта записи xlog для последнего изменения на этой странице |
pd_checksum | uint16 | 2 байта | Контрольная сумма страницы |
pd_flags | uint16 | 2 байта | Биты признаков |
pd_lower | LocationIndex | 2 байта | Смещение до начала свободного пространства |
pd_upper | LocationIndex | 2 байта | Смещение до конца свободного пространства |
pd_special | LocationIndex | 2 байта | Смещение до начала специального пространства |
pd_pagesize_version | uint16 | 2 байта | Информация о размере страницы и номере версии компоновки |
pd_prune_xid | TransactionId | 4 байта | Самый старый неочищенный идентификатор XMAX на странице или ноль при отсутствии такового |
Всю подробную информацию можно найти в src/include/storage/bufpage.h.
За заголовком страницы следуют идентификаторы элемента (ItemIdData), каждому из которых требуется 4 байта. Идентификатор элемента содержит байтовое смещение до начала элемента, его длину в байтах и несколько битов атрибутов, которые влияют на его интерпретацию. Новые идентификаторы элементов размещаются по мере необходимости от начала свободного пространства. Количество имеющихся идентификаторов элементов можно определить через значение pd_lower, которое увеличивается при добавлении нового идентификатора. Поскольку идентификатор элемента никогда не перемещается до тех пор, пока он не освобождается, его индекс можно использовать в течение длительного периода времени, чтобы ссылаться на элемент, даже когда сам элемент перемещается по странице для уплотнения свободного пространства. Фактически каждый указатель на элемент (ItemPointer, также известный как CTID), созданный PostgreSQL, состоит из номера страницы и индекса идентификатора элемента.
Сами элементы хранятся в пространстве, выделяемом в направлении от конца к началу незанятого пространства. Точная структура меняется в зависимости от того, каким будет содержание таблицы. Как таблицы, так и последовательности используют структуру под названием HeapTupleHeaderData, которая описывается ниже.
Последний раздел является "особым разделом", который может содержать всё, что необходимо методу доступа для хранения. Например, индексы-B-деревья хранят ссылки на страницы слева и справа, равно как и некоторые другие данные, соответствующие структуре индекса. Обычные таблицы не используют особый раздел вовсе (что указывается установкой значения pd_special равным размеру страницы).
Все строки таблицы структурированы одним и тем же образом. Они включают заголовок фиксированного размера (занимающий 23 байта на большинстве машин), за которым следует необязательная битовая карта пустых значений, необязательное поле идентификатора объекта и данные пользователя. Подробное описание заголовка представлено в Таблица 59-4. Актуальные пользовательские данные (столбцы строки) начинаются после смещения, заданного в t_hoff, которое должно всегда быть кратным величине MAXALIGN для платформы. Битовая карта пустых значений имеется тогда, когда бит HEAP_HASNULL установлен в значении t_infomask. В случае наличия, она начинается сразу после фиксированного заголовка и занимает достаточно байтов, чтобы иметь один бит на столбец (т. е. t_natts битов всего). В этом списке битов установленный в единицу бит означает непустое значение, а установленный в ноль соответствует пустому значению. Когда битовая карта отсутствует, все столбцы считаются непустыми. Идентификатор объекта присутствует, если только бит HEAP_HASOID установлен в значении t_infomask. Если он есть, он расположен сразу перед началом t_hoff. Любое заполнение, необходимое для того, чтобы сделать t_hoff кратным MAXALIGN, будет расположено между битовой картой пустых значений и идентификатором объекта. (Это в свою очередь гарантирует, что идентификатор объекта будет правильно выровнен.)
Таблица 59-4. Данные заголовка строки таблицы (HeapTupleHeaderData)
Поле | Тип | Длина | Описание |
---|---|---|---|
t_xmin | TransactionId | 4 байта | значение XID вставки |
t_xmax | TransactionId | 4 байта | значение XID удаления |
t_cid | CommandId | 4 байта | значение CID для вставки и/или удаления (пересекается с t_xvac) |
t_xvac | TransactionId | 4 байта | XID для операции VACUUM, которая перемещает версию строки |
t_ctid | ItemPointerData | 6 байт | текущее значение TID этой или более новой версии строки |
t_infomask2 | uint16 | 2 байта | количество атрибутов плюс различные биты флагов |
t_infomask | uint16 | 2 байта | различные биты флагов |
t_hoff | uint8 | 1 байт | отступ до пользовательских данных |
Всю подробную информацию можно найти в src/include/access/htup.h.
Интерпретация текущих данных может быть проведена с помощью информации, полученной из других таблиц, в основном из pg_attribute. Ключевые значения, необходимые для определения расположения полей attlen и attalign. Не существует способа непосредственного получения заданного атрибута кроме случая, когда имеются только поля фиксированной длины, и при этом нет пустых значений. Все эти особенности учитываются в функциях heap_getattr, fastgetattr и heap_getsysattr.
Чтобы прочитать данные, необходимо просмотреть каждый атрибут по очереди. В первую очередь нужно проверить, является ли значение поля пустым согласно битовой карте пустых значений. Если это так, можно переходить к следующему полю. Затем следует убедиться, что выравнивание является верным. Если это поле фиксированной ширины, берутся просто все его байты. Если это поле переменной длины (attlen = -1), всё несколько сложнее. Все типы данных с переменной длиной имеют общую структуру заголовка struct varlena, которая включает общую длину сохранённого значения и некоторые биты флагов. В зависимости от установленных флагов, данные могут храниться либо локально, либо в таблице TOAST. Также, возможно сжатие данных (см. Раздел 59.2).
Примечания
[1] | Фактически индексные методы доступа не нуждаются в этом формате страниц. Все существующие индексные методы в действительности используют этот основной формат, но данные, хранящиеся в индексных метастраницах обычно не следуют правилам компоновки. |
Пред. | Начало | След. |
Слой инициализации | Уровень выше | Внутренний интерфейс BKI |