feed_entries
Rails と postgresql を使用して RSS フィードを読み取るための単純なアプリを作成しましたが、複数のフィードからの投稿についてテーブルにクエリを実行しようとすると、パフォーマンスの問題が発生します。クエリの例は次のようになります。特定のフィード 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 万行あり、Fugu プランを使用して Heroku Postgres でホストされており、次のようないくつかのインデックスがあります。
"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 回目には全体が 2 ミリ秒しかかからないことがわかります。これは単に最初のクエリの結果がキャッシュされているためかもしれませんが、それでも混乱します。クエリを実行する前に実行も試みVACUUM ANALYZE
ましたが、ほとんど違いはありませんでした。さらに、単一の feed_id についてテーブルにクエリを実行すると、クエリ プランナーは を使用しIndex Scan Backward using index_feed_entries_on_feed_id_and_published_at on feed_entries
、合計実行時間は 20 ミリ秒程度と大幅に短縮されます。
この比較的単純な IN クエリのパフォーマンスを最適化するために採用できる他の戦略はありますか?