我使用 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 查询的性能吗?