我有一个7列的表,其中5个将为空。我将在int
,text
,date
,boolean
和money
数据类型上有空列。这张表格将包含数百万行有许多空值的行。恐怕空值将占据空间。在PostgreSQL中可空列是否占用额外的空间?
另外,你知道如果Postgres索引空值?我想阻止它索引空值。
我有一个7列的表,其中5个将为空。我将在int
,text
,date
,boolean
和money
数据类型上有空列。这张表格将包含数百万行有许多空值的行。恐怕空值将占据空间。在PostgreSQL中可空列是否占用额外的空间?
另外,你知道如果Postgres索引空值?我想阻止它索引空值。
基本上,NULL
值占用1位在NULL位图中。但它并不那么简单。
空位图(每行)仅当该行中至少有一列包含NULL
值时才存在。这可能会导致9列或更多列的表中出现悖论效应:将第一个NULL
值分配给列可能占用磁盘空间而不是写入数值。相反,如果最后一列变为非空,则会为该行删除空位图。
在物理上,最初为空的位图占用1字节的HeapTupleHeader
(23字节)之间的和实际的列数据或行OID
(如果仍然应该使用) - 这总是开始在MAXALIGN
的倍数(通常为8字节)。这留下了1字节由初始空位图使用的填充。
实际上对于8列或更少的表格,NULL存储空间是完全免费的。
之后,另一个MAXALIGN
字节(通常为8)分配给下一个MAXALIGN * 8
列(通常为64)。等
更多细节in the manual并根据这些相关的问题:
一旦你理解数据类型的对齐填充,您可以进一步优化存储:
但情况是罕见的,你可以节省大量的空间。通常这是不值得的。
@Daniel已经涵盖了对索引大小的影响。
我相信每个人都会使用位图中的单个位作为行。请参阅:http://www.postgresql.org/docs/9.0/static/storage-page-layout.html#HEAPTUPLEHEADERDATA-TABLE
NULL
值是否到达索引或至少取决于索引的类型。 基本上,这将是YES为btree
和gist
的索引类型,NO为hash
,它似乎YES或取决于PostgreSQL的版本NO为gin
索引类型。
pg_catalog.pg_am
表中有一个布尔型列amindexnulls
,它载有这些信息,但它已经在9.1中消失了。可能因为指标在PG改进中变得更加复杂。
在您的数据的具体情况下,最好的方法是测量索引的大小差异,使用pg_relation_size('index_name')
函数,在完全为NULL的内容和完全非NULL的内容之间,使用精确的PG版本,确切的数据类型,确切的索引类型和定义。并且可能知道,任何这些参数的未来变化都可能改变结果。
但在任何情况下,如果你“只是”想避免索引空值,它总是可以创建一个部分索引:
CREATE INDEX partial_idx(col) ON table WHERE (col is not null)
这将需要更少的空间,但是否这是怎么回事帮助或不利用查询的性能取决于这些查询。
+1有洞察力。对于部分索引,重要的是要注意,如果查询计划程序可以验证查询中是否包含该条件,那么它们只能被查询计划程序使用。查询规划器很聪明,但在这方面无法解决复杂的逻辑。或多或少逐字匹配'WHERE'子句以确保可以使用索引(可能有更多条件的“AND”编辑)。 [手册中的详细信息](http://www.postgresql.org/docs/current/interactive/indexes-partial.html)。 –
很酷......谢谢您的深刻解答 – Luke101
“对于8列或更少的表格,NULL存储空间是完全免费的。” - 如果只有一列保留为空,会怎么样?这意味着只有1个字节的空位图才会保存1位? – Dejell
如果存在任何空值,并且有足够的字节来覆盖所有列,并且加上“MAXALIGN”的下一个倍数,则会出现空位图。 –
谢谢欧文。仍然不确定 - 如果我没有任何空值,该怎么办?它仍然会在那里吗? (多对多表) – Dejell