Postgres 仅索引扫描耗时太长
Posted
技术标签:
【中文标题】Postgres 仅索引扫描耗时太长【英文标题】:Postgres index-only scan taking too long 【发布时间】:2019-08-28 23:52:33 【问题描述】:我有一个具有以下结构和索引的表:
Table "public.client_data"
Column | Type | Modifiers
-------------------------+---------+-----------
account_id | text | not_null
client_id | text | not null
client_type | text | not null
creation_time | bigint | not null
last_modified_time | bigint | not null
Indexes:
"client_data_pkey" PRIMARY KEY, btree (account_id, client_id)
"client_data_last_modified_time_index" btree (last_modified_time)
我需要从这个表中找到最旧的记录 - 为此我使用了以下查询:
SELECT last_modified_time FROM client_data ORDER BY last_modified_time ASC LIMIT 1;
但是,在 AWS Aurora Postgres 9.6 中的 db.r4.2xlarge RDS 实例中,此表上大约 6100 万行的查询运行速度非常慢(90-100 分钟),没有其他并发查询在运行。
但是,将查询更改为使用 DESC
会立即完成。可能是什么问题呢?我期待,因为我有一个 last_modified_time
的索引,仅查询由该列排序并应用了限制的列将涉及一个仅索引查询,该查询应在索引中的第一个条目之后停止。
这里是解释分析的输出:
EXPLAIN ANALYZE SELECT last_modified_time FROM client_data ORDER BY last_modified_time ASC LIMIT 1;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.57..2.31 rows=1 width=8) (actual time=6297823.287..6297823.287 rows=1 loops=1)
-> Index Only Scan using client_data_last_modified_time_index on client_data (cost=0.57..1049731749.38 rows=606590292 width=8) (actual time=6297823.287..6297823.287 rows=1 loops=1)
Heap Fetches: 26575013
Planning time: 0.078 ms
Execution time: 6297823.306 ms
DESC
版本的查询结果相同
EXPLAIN ANALYZE SELECT last_modified_time FROM client_data ORDER BY last_modified_time DESC LIMIT 1;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.57..2.32 rows=1 width=8) (actual time=2.265..2.266 rows=1 loops=1)
-> Index Only Scan Backward using client_data_last_modified_time_index on client_data (cost=0.57..1066049674.69 rows=611336085 width=8) (actual time=2.264..2.264 rows=1 loops=1)
Heap Fetches: 9
Planning time: 0.095 ms
Execution time: 2.278 ms
任何指针?
【问题讨论】:
看起来 postgres 经常访问堆,可能是为了检查旧行的可见性。 autovacuum 是否跟上此表中的更改? 不确定,但自动吸尘器最近运行过,可能是这样。 是否有可能有很多 first 相同的 last_modified_time(与ASC
),但只有少数 last last_modified_time(与 @987654329 @)?
【参考方案1】:
区别是这样的:
缓慢的计划有
Heap Fetches: 26575013
快速计划
Heap Fetches: 9
堆提取是将快速的仅索引扫描转变为慢速的普通索引扫描。
该表最近是否经历过大规模更新或删除?
缓慢扫描的原因是它必须在第一次匹配之前遍历许多不可见(已删除)的元组。
在桌子上运行VACUUM
,两次扫描都会很快。
【讨论】:
我们确实对表进行了删除操作,删除了超过 30 天的数据。删除完成后,我们运行最旧的记录查询以进行监控。运行最旧记录查询时,删除已完成,直到最旧记录查询完成后才会运行。此外,ASC 和 DESC 查询可互换运行多次,每次 DESC 查询完成但 ASC 查询卡住。 我的错,我没有注意到LIMIT
。我已经更新了答案。
谢谢。我会试试的。您之前的文章链接提供了非常丰富的信息。以上是关于Postgres 仅索引扫描耗时太长的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Postgres 在使用覆盖索引时仍然进行位图堆扫描?