Ответ 1
Расчет размера строки намного сложнее.
Хранение обычно разбивается на страницы данных . Существует небольшая фиксированная накладная плата на странице, возможные остатки не достаточно большие, чтобы соответствовать другим кортежам, и, что более важно, мертвые строки или процент, первоначально зарезервированный с помощью параметра FILLFACTOR
.
Что еще более важно, есть накладные расходы на строку (кортеж). HeapTupleHeader
из 23 байтов и выравнивание дополнений. Начало заголовка кортежа, а также начало данных кортежа выравниваются с кратким значением MAXALIGN
, который составляет 8 байтов на типичной 64-битной машине. Некоторые типы данных требуют согласования с следующим кратным 2, 4 или 8 байтов.
Указание руководства в системной таблице pg_tpye
:
typalign
- это выравнивание, требуемое при сохранении значения этого типа. Он применяется для хранения на диске, а также для большинства представлений значение внутри PostgreSQL. При сохранении нескольких значений последовательно, например, в представлении полной строки на диск, прокладка вставлена перед базой данных этого типа, чтобы она начинается с указанной границы. Ссылка на выравнивание - это начало первой точки отсчета в последовательности.Возможные значения:
c
=char
выравнивание, т.е. не требуется выравнивание.
s
=short
выравнивание (2 байта на большинстве машин).
i
=int
выравнивание (4 байта на большинстве машин).
d
=double
выравнивание (8 байтов на многих машинах, но далеко не все).
Ознакомьтесь с основными сведениями в руководстве здесь.
Ваш пример
Это приводит к 4 байтам заполнения после столбцов 3 integer
, потому что для столбца timestamp
требуется выравнивание double
и ему нужно начинать с следующего кратного 8 байтов.
Итак, одна строка занимает:
23 -- heaptupleheader
+ 1 -- padding or NULL bitmap
+ 12 -- 3 * integer (no alignment padding here)
+ 4 -- padding after 3rd integer
+ 8 -- timestamp
+ 0 -- no padding since tuple ends at multiple of MAXALIGN
Наконец, в заголовке страницы есть указатель ItemData
(указатель на элемент) для каждого кортежа (как отмеченный @AH в комментарии), который занимает 4 байт:
+ 4 -- item pointer in page header
------
= 52 bytes
Итак, мы приходим к наблюдаемым 52 байтам.
Расчет pg_relation_size(tbl) / count(*)
является пессимистической оценкой. pg_relation_size(tbl)
включает в себя раздувание (мертвые строки) и зарезервированное пространство FILLFACTOR
, а также накладные расходы на каждую страницу данных и таблицу. (И мы даже не упоминали сжатие для длинных данных varlena в таблицы TOAST, так как здесь это не применимо.)
Вы можете установить дополнительный модуль pgstattuple и вызвать SELECT * FROM pgstattuple('tbl_name');
для получения дополнительной информации о размере таблицы и кортежа.
Связанный ответ: