Postgres 选择 BTREE 而不是 BRIN 索引

Posted

技术标签:

【中文标题】Postgres 选择 BTREE 而不是 BRIN 索引【英文标题】:Postgres choosing BTREE instead of BRIN index 【发布时间】:2017-06-25 05:25:03 【问题描述】:

我正在运行 Postgres 9.5 并且正在使用 BRIN 索引。我有一个包含大约 1.5 亿行的事实表,我正试图让 PG 使用 BRIN 索引。我的查询是:

select sum(transaction_amt), 
       sum (total_amt) 
from fact_transaction 
where transaction_date_key between 20170101 and 20170201 

我在 transaction_date_key 列上同时创建了 BTREE 索引和 BRIN 索引(默认 pages_per_range 值为 128)(上述查询是指 2017 年 1 月到 2017 年 2 月)。我原以为 PG 会选择使用 BRIN 索引,但它与 BTREE 索引一起使用。这是解释计划:

https://explain.depesz.com/s/uPI

然后我删除了 BTREE 索引,对表进行了清理/分析,然后重新运行查询,它确实选择了 BRIN 索引,但是运行时间要长得多:

https://explain.depesz.com/s/5VXi

事实上,当使用 BTREE 索引而不是 BRIN 索引时,我的测试都更快。我以为它应该是相反的?

我更喜欢使用 BRIN 索引,因为它的大小更小,但是我似乎无法让 PG 使用它。

注意:我加载了从 2017 年 1 月到 2017 年 6 月的数据(通过 transaction_date_key 定义),因为我读到物理表排序在使用 BRIN 索引时会有所不同。

有谁知道为什么 PG 选择使用 BTREE 索引以及为什么 BRIN 在我的情况下要慢得多?

【问题讨论】:

你能告诉我们explain (analyze, verbose, buffers, timing)的输出而不是“just”explain (analyze) 当然 - 现在运行它们。 B-Tree 和 BRIN:explain.depesz.com/s/S3Zp 仅限 BRIN:explain.depesz.com/s/Z1A5 我自己没有使用过 BRIN 索引,但我的理解是,只有当您的数据以与您的查询和 BRIN 索引匹配的方式在磁盘上排序时,它们才能正常工作。您是否尝试在您的表上运行 CLUSTER? 对不起,不去那里。我试图对表进行聚类,但是使用 BRIN 类型索引似乎无法进行聚类。我输入了CLUSTER fact_transaction USING i_fact_transaction_transaction_date_key;,但它返回ERROR: cannot cluster on index "i_fact_transaction_transaction_date_key" because access method does not support clustering SQL state: 0A000 【参考方案1】:

似乎 BRIN 索引扫描不是很有选择性——它返回 3000 万行,所有这些都必须重新检查,这就是花费时间的地方。

这可能意味着transaction_date_key 与表中行的物理位置没有很好的相关性。

BRIN index works 由表块的范围“集中在一起”(可以使用存储参数pages_per_range 配置多少,其默认值为 128)。存储块范围的索引值的最大值和最小值。

所以你的表中有很多块范围在2017010120170201之间包含transaction_date_key,并且必须扫描所有这些块以计算查询结果。

我看到了两种改善情况的选择:

降低pages_per_range 存储参数。这会使索引变大,但会减少“误报”块的数量。

transaction_date_key 属性上对表进行聚类。正如您所发现的,这需要(至少暂时)列上的 B 树索引。

【讨论】:

以上是关于Postgres 选择 BTREE 而不是 BRIN 索引的主要内容,如果未能解决你的问题,请参考以下文章

mysql btree和hash索引对比

在 psql 中可见的 Postgres 表,而不是来自 jdbc

为每个用户选择最新条目而不使用 group by (postgres)

Postgres为连接表的array_agg返回[null]而不是[]

如何使用 Django 功能而不是所有键来索引刚刚选择的 json 键?

Node-Postgres/Knex 在 JS 中返回 CITEXT[] 作为字符串,而不是字符串数组