将长列表中的任何值与 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 将它们合并回一个查询。
架构:
# 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 将它们合并回一个查询。