簡體   English   中英

如何減少有序結果的Postgresql IN查詢的索引掃描時間?

[英]How to reduce index scan time for a postgresql IN query with ordered results?

我構建了一個簡單的應用程序,用於使用rails和postgresql讀取RSS feed,但是當我嘗試在feed_entries表中查詢來自多個feed的帖子時, feed_entries性能問題。 查詢示例如下所示,以檢索給定的Feed 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毫秒,這可能僅僅是因為第一個查詢的結果已被緩存,但是這仍然讓我感到困惑。 在運行查詢之前,我也嘗試運行VACUUM ANALYZE ,但差異不大。 另外,如果我在表中查詢單個feed_id,那么查詢計划者將Index Scan Backward using index_feed_entries_on_feed_id_and_published_at on feed_entries ,並且總執行時間要快得多,約為20ms。

我是否可以采用其他策略來優化此相對簡單的IN查詢的性能?

要嘗試的另一件事是這種替代查詢形式:

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 ,這可能會給您帶來一點點提升,但是有效性會隨着大量更新而降低。 閱讀此相關答案的最后一章以獲取更多信息:
位圖堆掃描性能

當然, 有關性能優化的所有常規建議也適用。

嘗試使用DESC順序創建索引。 例如。

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

您可以在(feed_id,published_at desc)上嘗試與上述類似的(復合)索引,以查看其工作原理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM