我有一个 PostgreSQL 15 部署,其中包含数千万条记录的分区表。
我一直在尝试创建索引,我对 Btree 索引占用的空间如此之小感到惊讶。
因此,分区表dummy_name_partition_01
中大约有 1300 万条记录。不确定是否相关,但记录可能会变得有点大,平均每条记录 2.66 KiB(不计算索引,分区大约有 30 GiB)。
其中一列(名为record_type
)是我正在使用索引处理的列,它存储了一个小字符串(<50 个字符)。虽然它是 TEXT 类型而不是 ENUM,但它的值始终是大约 300 个可能的字符串之一。
我最初为该record_type
列创建了一个 BRIN 索引,以节省磁盘使用量。看起来索引大小在磁盘上只有大约 1 MiB。确实很小。
现在,我在使用 BRIN 索引时遇到了问题。它坚持进行顺序扫描,所以 brin 索引好像没用。我担心 btree 索引会太大,但后来我删除了 BRIN 索引并将其创建为 BTREE,它的大小只有 92 MiB。我预计至少在 1 GiB 范围内!
为了测量索引大小,我查询了information_schema.tables
表并使用了函数pg_table_size
。pg_indexes_size
也就是说,我在没有索引时使用查询索引大小pg_indexes_size
,然后在创建索引后运行它,并将差值作为索引大小。当然,我这样做了几次,这样我就可以从 BRIN 和 BTREE 中获得数字。
该索引与 btree 索引一样简单,与brin 索引CREATE INDEX foo_bar ON dummy_namy_partition_01 (record_type)
一样。USING BRIN
现在,我想知道:Postgres 是否以某种方式将指向列中数据的指针存储起来record_type
,而不是到处存储重复的字符串,那么这就是索引位于近一百个 MiB 而不是几 GB 的原因吗?或者,这里发生了什么?
B 树索引键重复数据删除功能在 PostgreSQL 13 中实现;默认情况下,此功能有效,如果页面上的所有元组都具有相同的键值,则会将多个索引元组折叠为单个键值和 TID 列表。毫不奇怪,它对于低基数的键很有效。