我有一个大约 35M 行的表,并尝试查找“已处理”记录以不时删除。有效状态有 14 个,已处理 10 个。
id uuid default uuid_generate_v4() not null primary key,
fk_id uuid not null references fk_table,
-- ... other columns
created_date timestamptz default now() not null,
status varchar(128) not null
索引在
(status,created_date)
。select id from table
where created_date < 'somedate'
and status = ANY('{a,b,c..10}')
查询规划器坚持使用完整的 seq_scan,而不是索引。
有什么技巧可以让 Postgres 使用谓词的
status = ANY
部分的索引吗?
如果超过百分之几的行符合条件 - 或者更确切地说,如果 Postgres 估计 一样多 - 它将选择顺序扫描,对于这种情况,这会更快。
如果事实上只有少数行符合条件,那么您的列统计信息(和/或成本设置)应该归咎于误导性的估计。
如果引用的索引仅用于手头的目的,并且只有相对较少的行具有“已处理”状态,请将其替换为部分索引:
CREATE INDEX foo ON tbl (created_date) WHERE status = ANY('{a,b,c..10}')
将使索引更小,查询更快,并且使用它的可能性更大。
无论哪种方式,至少增加一点
created_date
和状态的统计目标很可能是有帮助的。参见:
无论哪种方式,仅对于“14个有效状态”,
status varchar(128)
似乎非常浪费。
更多取决于缺失的细节......