27

我有一个有 7 列的表,其中 5 列将为空。int我将在、textdatebooleanmoney数据类型上有一个空列。该表将包含数百万行,其中包含许多空值。恐怕空值会占用空间。

另外,你知道 Postgres 是否索引空值吗?我想防止它索引空值。

4

3 回答 3

49

基本上,值在 NULL 位图中NULL占据1 位。但这并不是那么简单。

空位(每行)仅在该行中至少有一列包含NULL值时才分配。这可能会在具有 9 列或更多列的表中导致看似自相矛盾的效果:将第一个NULL值分配给列可能会比向其写入值占用更多的磁盘空间。相反,从行中删除最后一个 NULL 值也会删除 NULL 位图。

物理上,初始空位图在(23 字节)和实际列数据或行(如果您仍然应该使用它)之间占用1 个字节- 它始终以(通常为8 字节)的倍数开始。这会留下1 个字节的填充,供初始空位图使用。HeapTupleHeaderOIDMAXALIGN

实际上,对于 8 列或更少列的表(包括已删除但尚未清除的列) , NULL 存储是完全免费的。
之后,为接下来的列(通常为 64)MAXALIGN分配另一个字节(通常为 8个)。MAXALIGN * 8等等。

手册中和这些相关问题下的更多详细信息:

了解数据类型的对齐填充后,您可以进一步优化存储:

但是,您可以节省大量空间的情况很少见。通常不值得努力。

@Daniel已经涵盖了对索引大小的影响。

请注意删除的列(尽管现在不可见)保留在系统目录中,直到重新创建表。那些僵尸可以强制分配(放大的)NULL 位图。看:

于 2012-08-27T18:04:53.007 回答
14

值是否NULL到达索引至少取决于索引的类型。基本上,对于和索引类型,这将是YES,对于,对于索引类型,这似乎是 YES 或 NO 具体取决于 PostgreSQL 版本。btreegisthashgin

表格中曾经有一个布尔列amindexnullspg_catalog.pg_am承载该信息,但在 9.1 中它已经消失了。可能是因为索引在 PG 改进中变得更加复杂。

在您的数据的特定情况下,最好的了解方法是使用pg_relation_size('index_name')函数测量索引的大小差异,在完全 NULL 和完全 NOT NULL 的内容之间,使用您的确切 PG 版本、确切数据类型、确切索引类型和定义. 并且知道,未来任何这些参数的变化都可能改变结果。

但无论如何,如果您“只是”想避免索引 NULL,则始终可以创建部分索引:

CREATE INDEX partial_idx(col) ON table WHERE (col is not null)

这将占用更少的空间,但这是否有助于查询的性能取决于这些查询。

于 2012-08-27T17:16:08.630 回答
2

我相信每个人都会在该行的位图中使用一个位。见这里:http ://www.postgresql.org/docs/9.0/static/storage-page-layout.html#HEAPTUPLEHEADERDATA-TABLE

于 2012-08-27T16:31:13.073 回答