将长列表中的任何值与 postgres GIN 索引匹配

Match any value from a long list with a postgres GIN index

架构:

# Table name: foos
#
#  id       :integer  not null, primary key
#  bar_ids  :integer  is an Array
#
# Indexes
#
#  index_foos_on_bar_ids    (bar_ids) USING gin

查询:

SELECT * FROM foos
WHERE (
  bar_ids && '{
    28151247,
    17295392,
    …300 more bar_ids…,
    29368568,
    45191356
  }')

这会导致顺序扫描非常慢。我尝试重写为一系列 OR,但这只是给了我一个并行顺序扫描。将它拆分成更小的查询是可行的——在切换到一个低效的计划之前它最多可以处理大约 70 个词——但这需要 运行 更多的查询。有什么方法可以编写查询以获得更有效的计划吗?

我找到的最佳解决方案是暂时禁用顺序扫描:

SET LOCAL enable_seqscan = 'off';

这应该只是为了连接。您可以使用 SHOW enable_seqscan;.

检查它

这迫使计划者利用 index_foos_on_bar_ids 索引和 运行 更快的查询。

我不太推荐的另一种方法是将一个大查询拆分为许多较小的查询,所有这些都低于使用顺序扫描的阈值,并使用UNION 将它们合并回一个查询。