首页 > 解决方案 > Postgres 仅索引扫描耗时太长

问题描述

我有一个具有以下结构和索引的表:

     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

任何指针?

标签: databasepostgresqlquery-optimizationrdbms

解决方案


区别在于:

缓慢的计划有

Heap Fetches: 26575013

和快速计划

Heap Fetches: 9

堆提取是将快速仅索引扫描转换为慢速正常索引扫描的原因。

表最近是否经历过大规模更新或删除?

缓慢扫描的原因是它必须在第一次匹配之前遍历许多不可见(已删除)的元组。

在桌子上运行VACUUM,两次扫描都会很快。


推荐阅读