RDS 上非常慢的简单 PostgreSQL 查询

eas*_*yjo 7 postgresql performance index index-tuning postgresql-performance

我似乎在中型 RDS 盒子(db.m3.medium,3.7gb ram)上的查询速度很慢。

这是一个包含 4,152,928 行的表格。

select sum(some_field) c
from pages
where pages.some_id=123
and pages.first_action_at > '2014-01-01 00:00:00 +1000'
Run Code Online (Sandbox Code Playgroud)

总运行时间:45031 毫秒。
在本地,我有大约 110 万行,同样的查询需要大约 450 毫秒。

这是查询计划,来自解释:

Aggregate  (cost=475640.59..475640.60 rows=1 width=4)
   ->  Seq Scan on pages  (cost=0.00..475266.07 rows=149809 width=4)
         Filter: ((first_action_at > '2014-01-01 00:00:00'::timestamp without time zone) 
                AND (some_id = 447))
Run Code Online (Sandbox Code Playgroud)

这是来自解释分析的回应:

 Aggregate  (cost=475641.74..475641.76 rows=1 width=4) (actual time=42419.717..42419.718 rows=1 loops=1)
   ->  Seq Scan on pages  (cost=0.00..475267.22 rows=149810 width=4) (actual time=0.013..42265.908 rows=141559 loops=1)
    Filter: ((first_action_at > '2014-01-01 00:00:00'::timestamp without time zone) AND (some_id = 447))
    Rows Removed by Filter: 4011369
Run Code Online (Sandbox Code Playgroud)

总运行时间:42419.772 毫秒

作为参考,141559 行是 sum() 的一部分。

我目前拥有的索引是:

:some_id
:some_id, :first_action_at
Run Code Online (Sandbox Code Playgroud)

work_mem之前设置为 1 mb(RDS 默认值)。我刚刚将其更改为 18 MB。

编辑:似乎可以通过增加work_mem和添加上面的第二个索引来解决,速度现在约为 800 毫秒。

Erw*_*ter 8

匹配索引

重新阅读您的问题后,我意识到您运行的不是 Amazon Redshift,而是 Amazon RDS,它似乎正在运行未受污染的 Postgres,至少根据文档

Amazon RDS 支持运行多个 PostgreSQL 版本的数据库实例。目前我们支持 PostgreSQL 版本 9.3.1、9.3.2 和 9.3.3。

这意味着您可以使用仅索引扫描。如果您满足一些先决条件(基本上如果vacuum可以跟上写操作)并且如果some_field没有经常更新并且相当小(这似乎是数字列的情况),那么完美的索引将包含some_field在最后一个位置(如@zerkms首先提到):

CREATE INDEX ON pages(some_id, first_action_at, some_field);
Run Code Online (Sandbox Code Playgroud)

请注意,some_id应该在之前 first_action_at,因为首先让列进行相等性检查,然后再进行范围检查通常会更有效。详细信息:多列
索引和性能

如果您在 中没有看到“仅索引扫描” EXPLAIN ANALYZE,则最后一列只是压舱物,最好将其保留:

CREATE INDEX ON pages(some_id, first_action_at);
Run Code Online (Sandbox Code Playgroud)

(就像你现在一样,根据你的问题更新。)

无论哪种方式,另一个索引(some_id)只提供很少的多列索引:
复合索引是否也适用于第一个字段的查询?

服务器配置

所有关于慢查询和正确服务器配置常见建议都适用work_mem,1 MB的设置对于具有数百万行的数据库来说太低了。但是这个特定的设置对于这个特定的查询不应该是至关重要的,因为work_mem是(每个文档):

内部排序操作和哈希表使用的内存。

两者都不适用于这里。