postgresql - Postgres 选择 BTREE 而不是 BRIN 索引

标签 postgresql indexing postgresql-9.5

我正在运行 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 月至 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 在我的情况下这么慢?

最佳答案

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

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

A BRIN index works通过将表 block 的范围“集中在一起”(多少可以使用存储参数 pages_per_range 进行配置,其默认值为 128)。存储每个 block 的索引值的最大值和最小值。

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

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

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

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

关于postgresql - Postgres 选择 BTREE 而不是 BRIN 索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42098803/

相关文章:

java - 使用 Hibernate 保存在 @ManyToMany 关联中

python - geodjango syncdb 错误。来自 geodjango 教程

c++ - xtensor xt::where与索引相关的功能出现问题

sql-server - SQL Server - 何时使用聚集索引与非聚集索引?

ruby-on-rails - Rails 应用程序 - 返回用户名的 Object_ID

sql - 连接两个包含 INNER JOINS 的查询

elasticsearch - 如何计算Elasticsearch字段大小

sql - 按关联的表属性分组和排序

javascript - Upsert 正在复制条目,我该如何防止这种情况发生?

json - 以逗号分隔的列表形式返回 jsonb_array_elements 结果