[英]Postgres IN clause with many values not using partial index
我正在使用Postgres 9.2.24。
我有一个名为_order
的表,该表约有100,000,000行。 该表有一个名为merged_id int8
的列。 约有2,000,000个_order
行具有merged_id
值,其余的为null。
我在搜索_order
使用查询时发现了两种不同的Postgres行为
select * from _order where merged_id in ( 10001 ,10002 ,10003 ....., 11000);
如果我创建这样的索引:
create index order_merged_id_index on _order(merged_id);
无论in子句中有多少id(测试范围为1到50到100到200到1000), EXPLAIN
显示搜索将使用index_scan
。
但是,如果我改为创建此部分索引:
create index order_merged_id_index on _order(merged_id) where merged_id is not null;
EXPLAIN
在WHERE
子句中显示了seq_scan
,其中包含100个以上的id编号。
为什么是这样?
有什么办法解决吗?
有许多可能的原因。 我怀疑过时版本的选择性估计存在缺陷。 我隐约记得用于数组的查询计划的最大值为100,后来进行了改进。 IN
表达式通常在内部转换为= ANY (ARRAY[...]
):
无论哪种方式,您都可以通过在查询中重复部分索引的谓词来解决此问题:
SELECT * FROM _order
WHERE merged_id IN ( 10001 ,10002 ,10003 ....., 11000)
AND merged_id is not null; -- logically redundant
您的服务器配置可能还存在其他问题,例如费用设置或表格统计信息:
并且不要忘记在创建部分索引之后至少对表运行ANALYZE
。 或者,最好是VACUUM ANALYZE
,但这对于您的大桌子来说更昂贵。
但是,对于较长的值列表,可以使用以下更有效的查询变量:
SELECT o.*
FROM unnest('{10001 ,10002 ,10003 ....., 11000}'::int8[]) merged_id
JOIN _order o USING (merged_id);
看到:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.