【问题标题】:Do nullable columns occupy additional space in PostgreSQL?可以为空的列在 PostgreSQL 中是否会占用额外的空间?
【发布时间】:2023-03-12 13:48:01
【问题描述】:

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

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

【问题讨论】:

    标签: postgresql database-design indexing null


    【解决方案1】:

    基本上,NULL 值在 NULL 位图中占据 1 位。但事情没那么简单。

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

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

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

    更多详情in the manual 并在这些相关问题下:

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

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

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

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

    【讨论】:

    • "对于 8 列或更少列的表,NULL 存储是完全免费的。" - 如果只有 1 列为空怎么办?这意味着将创建 1 字节的空位图仅用于保存 1 位?
    • 如果有任何空值,则空位图存在,有足够的字节覆盖所有列,加上填充到MAXALIGN 的下一个倍数。
    • @Dejell:行中没有空值,也没有空位图。这在上面的答案中。点击链接了解更多详情。
    • 为什么文档说header占了23个字节(在大多数机器上),但是表中的长度之和等于27?
    • 是的,令人困惑。我想t_cid ... (overlays with t_xvac)there 意味着这两个项目共享相同的物理场。源代码中的注释也暗示了很多:doxygen.postgresql.org/htup__details_8h_source.html 第 72 行。
    【解决方案2】:

    NULL 值是否到达索引至少取决于索引的类型。 基本上,对于btreegist 索引类型,这将是YES,对于hash,这将是NO,看起来YES 或NO gin 索引类型取决于 PostgreSQL 版本。

    pg_catalog.pg_am 表中曾经有一个布尔列 amindexnulls 携带该信息,但在 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)
    

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

    【讨论】:

    • +1 有见地。对于部分索引,重要的是要注意它们只能由查询计划器使用,如果它可以验证条件是否包含在查询中。查询计划器很聪明,但无法解决这方面的复杂逻辑。或多或少地逐字匹配WHERE 子句以确保可以使用索引(可能AND-ed 有更多条件)。 Details in the manual.
    • 酷..感谢您富有洞察力的回答
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2020-06-12
      • 1970-01-01
      • 2021-02-04
      • 2020-11-01
      • 1970-01-01
      • 2018-06-11
      • 2021-09-10
      • 1970-01-01
      • 2019-03-11
      相关资源
      最近更新 更多