我有一个大表(40多个记录),其结构如下:
CREATE TABLE collected_data(
id TEXT NOT NULL,
status TEXT NOT NULL,
PRIMARY KEY(id, status),
blob JSONB,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
我需要获取updated_at
早于24小时且具有特定状态且blob不为空的所有(或至少100,000条)记录。
因此查询变为:
SELECT
id
FROM
collected_data
WHERE
status = 'waiting'
AND blob IS NOT NULL
AND updated_at < NOW() - '24 hours'::interval
LIMIT 100000;
这将导致执行计划如下:
Limit (cost=0.00..234040.07 rows=100000 width=12)
-> Seq Scan on collected_data (cost=0.00..59236150.00 rows=25310265 width=12)
" Filter: ((blob IS NOT NULL) AND (type = 'waiting'::text) AND (updated_at >= (now() - '24:00:00'::interval)))"
几乎总是导致全表扫描,这意味着某些查询确实很慢。
我试图创建像CREATE INDEX idx_special ON collected_data(status, updated_at);
这样的索引,但这无济于事。
有什么办法可以使查询速度更快?
答案 0 :(得分:1)
计划者认为25,310,265行将满足您的条件,因此认为通过seq扫描仅获取100,000个行,然后尽早停止将被破坏。如果实际上并没有那么多,或者有很多但它们都聚集在表的错误部分,那么实际上并不会那么快。如果在选择了100,000个之后,您下一步要做的是更新它们使其不再符合条件的方式,则可能是这种情况。因为那样的话,您必须不断走过去那些合格的残余物,才能找到下一批。
您可以通过在查询中添加“ order by Updated_at”来鼓励它使用索引。您还可以通过创建局部索引CREATE INDEX ON collected_data(status, updated_at) where blob is not null
或CREATE INDEX ON collected_data(updated_at) where status='waiting' and blob is not null
来堆叠甲板,以自己的喜好。