当数据对齐时,CPU可以有效地执行对内存的读写操作。因此,PostgreSQL中的每种数据类型都有特定的对齐要求。 当多个属性连续存储在元组中时,在属性之前插入填充。理解这些对齐要求有助于最小化在磁盘上存储元组时所需的填充量,从而节省磁盘空间。
Postgres中的数据类型分为以下几类:
1)按值传递,固定长度:通过值传递给Postgres内部例程并具有固定长度的数据类型属于此类别。长度可以是1,2或4(或64位系统上为8)字节。
2)传递引用,固定长度:对于这些数据类型,来自内存堆页面的地址引用将发送到内部Postgres例程。它们也有固定的长度。
3)传递引用,可变长度:对于可变长度数据类型,Postgres在实际数据之前添加变长标头。它存储数据实际上是如何存储在磁盘上(未压缩,压缩或TOAST)以及实际数据长度的一些信息。
通常,变长标头占用的磁盘大小为1字节。但是,如果数据无法被TOAST且未压缩数据的大小超过126个字节,则它会使用4字节的标头。此外,具有4字节变长标头的属性需要与4字节对齐的内存位置对齐。
4)传递引用,可变长度(cstring,unknown):这两种数据类型是字符串文字,它们不需要任何变长标头。
可以使用以下查询来检查每种类型的对齐要求,部分结果显示如下:
postgres=# select typname,typbyval,typlen,typalign from pg_type;
typname | typbyval | typlen | typalign
---------------------------------------+----------+--------+----------
bool | t | 1 | c
bytea | f | -1 | i
char | t | 1 | c
name | f | 64 | c
int8 | f | 8 | d
int2 | t | 2 | s
int2vector | f | -1 | i
int4 | t | 4 | i
regproc | t | 4 | i
text | f | -1 | i
oid | t | 4 | i
tid | f | 6 | s
xid | t | 4 | i
cid | t | 4 | i
oidvector | f | -1 | i
pg_type | f | -1 | d
其中typname是数据类型的名称。如果数据类型是按值传递访问,则typbyval为true,否则为false。 typlen是实际的数据类型长度,但是对于可变长度的数据类型,它的值小于0(对于cstring和unknown来说为-2,其他的为-1)。typalign是数据类型所需的对齐方式。
可以通过将各种数据类型以相应对齐方式有利的方式放置来减少填充空间。
在元组属性之前,存储一个固定大小的23字节元组标头,后跟一个可选的空位图和一个可选的对象ID。 这些属性始终从边界开始 ,通常在64位操作系统上为8个字节(或在32位操作系统上为4个字节)。 因此,最小元组标头的有效大小是24字节(23字节标头和1字节填充)。当存在空位图时,它会占用足够的字节以使每个数据列有一位。 在该位列表中,1位表示非空,0位表示空。 当位图不存在时,假定所有列都不为空。
By Kalath