yc *_*c l 3 sql postgresql indexing sql-in
我正在使用 Postgres 9.2.24。
我有一个以_order
大约 100,000,000 行命名的表。该表有一个名为 的列merged_id int8
。大约 2,000,000_order
行有一个merged_id
值,其余的为空。
我找到了两种不同的 Postgres 行为,我在其中_order
使用查询进行搜索
select * from _order where merged_id in ( 10001 ,10002 ,10003 ....., 11000);
Run Code Online (Sandbox Code Playgroud)
如果我创建这样的索引:
create index order_merged_id_index on _order(merged_id);
Run Code Online (Sandbox Code Playgroud)
无论 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;
Run Code Online (Sandbox Code Playgroud)
EXPLAIN
seq_scan
在WHERE
子句中显示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
Run Code Online (Sandbox Code Playgroud)
您的服务器配置可能存在其他问题,例如成本设置或表统计信息:
并且不要忘记ANALYZE
在创建部分索引后至少在您的表上运行一次。或者,最好是VACUUM ANALYZE
,但那对于你的大桌子来说更贵。
但是,对于很长的值列表,可以使用更有效的查询变体:
SELECT o.*
FROM unnest('{10001 ,10002 ,10003 ....., 11000}'::int8[]) merged_id
JOIN _order o USING (merged_id);
Run Code Online (Sandbox Code Playgroud)
看:
归档时间: |
|
查看次数: |
1403 次 |
最近记录: |