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)。存储块范围的索引值的最大值和最小值。
所以你的表中有很多块范围在20170101
和20170201
之间包含transaction_date_key
,并且必须扫描所有这些块以计算查询结果。
我看到了两种改善情况的选择:
降低pages_per_range
存储参数。这会使索引变大,但会减少“误报”块的数量。
在transaction_date_key
属性上对表进行聚类。正如您所发现的,这需要(至少暂时)列上的 B 树索引。
【讨论】:
以上是关于Postgres 选择 BTREE 而不是 BRIN 索引的主要内容,如果未能解决你的问题,请参考以下文章
在 psql 中可见的 Postgres 表,而不是来自 jdbc
为每个用户选择最新条目而不使用 group by (postgres)
Postgres为连接表的array_agg返回[null]而不是[]