在PostgreSQL中不使用NULL仍然会在头部使用NULL位图吗?

22

显然,PostgreSQL在每个数据库行的头部中存储一些值。

如果我在该表中不使用NULL值- null位图是否仍然存在?
定义列为NOT NULL是否有任何区别?

2个回答

38

实际情况比这更加复杂。

每行的空值位图需要一个字节对齐后的列数的位,只有在实际行包括至少一个 NULL 值且在这种情况下被完全分配时才存在。NOT NULL 约束不会直接影响此项。(当然,如果您的表的所有字段都是 NOT NULL,则永远不会有空值位图。)

"堆元组头"(每行)长23个字节。在此之后,实际数据从 MAXALIGN(最大数据对齐)的倍数开始,这在 64 位操作系统上通常为8个字节(32 位操作系统上为4个字节)。请以 root 身份从 PostgreSQL 二进制目录运行以下命令以获得确定的答案:

./pg_controldata /path/to/my/dbcluster

在典型的基于Debian的Postgres 12安装中,应该是这样的:

sudo /usr/lib/postgresql/12/bin/pg_controldata /var/lib/postgresql/12/main

无论哪种方式,标头和数据对齐的起始位置之间有一个空闲字节,可供空值位图利用。只要您的表具有8列或更少,则 NULL 存储在磁盘空间方面实际上是完全免费的

之后,另外MAXALIGN(通常为8字节)将被分配给空值位图,以覆盖另外(通常)64个字段,依此类推。

这适用于至少版本8.4-12,并且最有可能不会更改。


2
@DavidTan:这要看情况。如果一行中至少有一个 NULL 值,那么空值位图仅在该行上分配。在最坏的情况下,这可能意味着对第9列进行整个表重写。 - Erwin Brandstetter
在头部和对齐数据起始位置之间有一个自由字节,这意味着每个表都是这样 - 我说得对吗?如果有3列,8000行,并且其中一列始终为空 - 那么不需要8000位吗? - Dejell
1
@Dejell:每行的“free”字节是针对每一行的。对于只有3列,null位不会使物理存储变得更大。另外:如果这些列“始终”为null,那么您可以将其删除... - Erwin Brandstetter
因为 NULL 值在元组头中以位图的形式存储,所以我们可以说,在查询(大表)中 WHERE txt IS NULLWHERE txt='' 更快。请参考 https://stackoverflow.com/a/32081389/287948 的正确性(?)。 - Peter Krauss
1
@PeterKrauss:是的,但差别微乎其微,几乎无关紧要——而且仅适用于顺序扫描。通常,您需要为需要支持快速查询的列创建索引,这是一个改变游戏规则的因素。 - Erwin Brandstetter
显示剩余3条评论

3
空值位图仅在t_infomask中设置了HEAP_HASNULL位时才存在。如果存在,则它从固定头部之后开始,并占用足够的字节以每个数据列具有一个位(即,总共t_natts位)。在这个位列表中,1位表示非空,0位表示空值。当位图不存在时,所有列都被假定为非空。

http://www.postgresql.org/docs/9.0/static/storage-page-layout.html#HEAPTUPLEHEADERDATA-TABLE

每8列需要使用一字节额外的存储空间。那么,对于大约每一百万行,这将占用一兆字节的存储空间。似乎并不是很重要。我会根据需要定义表格,而不担心空标题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接