1

我使用 rails 和 postgresql 构建了一个简单的应用程序来读取 RSS 提要,但是当我尝试feed_entries从多个提要中查询我的表的帖子时遇到了性能问题。示例查询如下所示,用于检索给定提要 ID 集合的 20 个最新条目:

SELECT * FROM feed_entries WHERE feed_id IN (19, 21, 383, 1867, 3103) ORDER BY published_at DESC LIMIT 20;

feed_entries表有大约 400 万行,托管在 Heroku Postgres 上,采用 Fugu 计划,它有一些索引,包括:

"index_feed_entries_on_feed_id_and_published_at" btree (feed_id, published_at)
"index_feed_entries_on_published_at" btree (published_at)

以下是查询计划器的结果:

EXPLAIN ANALYZE SELECT * FROM feed_entries WHERE feed_id IN (19, 21, 383, 1867, 3103) ORDER BY published_at DESC LIMIT 20;

 Limit  (cost=4353.93..4353.94 rows=20 width=1016) (actual time=12172.275..12172.325 rows=20 loops=1)
   ->  Sort  (cost=4353.93..4355.07 rows=2286 width=1016) (actual time=12172.268..12172.284 rows=20 loops=1)
     Sort Key: published_at
     Sort Method: top-N heapsort  Memory: 52kB
     ->  Index Scan using index_feed_entries_on_feed_id_and_published_at on feed_entries  (cost=0.00..4341.76 rows=2286 width=1016) (actual time=8.612..12169.504 rows=630 loops=1)
           Index Cond: (feed_id = ANY ('{19,21,383,1867,3103}'::integer[]))
Total runtime: 12172.520 ms

规划器看起来像是在使用适当的索引,但扫描索引仍然需要大约 12 秒,这让我觉得对于一个有 400 万行的表来说太长了。如果我完全按照上面的方式重复查询计划器,那么第二次它告诉我整个事情只需要 2 毫秒,也许这只是因为第一次查询的结果被缓存了,但它仍然让我感到困惑。我也尝试VACUUM ANALYZE在运行查询之前运行,但差别不大。此外,如果我在表中查询单个 feed_id,则查询计划器使用Index Scan Backward using index_feed_entries_on_feed_id_and_published_at on feed_entries,并且总执行时间要快得多,大约为 20 毫秒。

我可以采用其他策略来优化这个相对简单的 IN 查询的性能吗?

4

2 回答 2

1

要尝试的另一件事是这种替代查询形式:

SELECT * 
FROM   feed_entries
JOIN  (unnest('{19,21,383,1867,3103}'::int[]) AS feed_id) sub USING (feed_id)
ORDER  BY published_at DESC
LIMIT  20;

不过,列的排序顺序在多列索引中确实很重要。采用:

CREATE index_feed_entries_2 ON feed_entries (feed_id, published_at DESC)

如果你CLUSTER根据这个索引你的表,这可能会给你带来一点点提升,但是随着大量更新,效率会下降。阅读此相关答案的最后一章以获取更多信息:
位图堆扫描性能

当然,所有关于性能优化的常见建议也适用。

于 2013-06-27T16:40:11.793 回答
0

尝试使用 DESC 顺序创建索引。例如。

create index feed_entries_published_at_desc_idx on feed_entries ( published_at desc ) with (fillfactor=100);

您可以在 (feed_id, published_at desc) 上尝试与上述类似的(复合)索引,看看它是如何工作的。

于 2013-06-27T15:50:13.170 回答