2014-01-27 170 views
19

當我添加limit 1時,我的查詢變得非常慢。PostgreSQL查詢速度非常慢,限制爲1

我有一個表object_values與時間戳值的對象:

timestamp | objectID | value 
-------------------------------- 
2014-01-27|  234 | ksghdf 

每對象我想要得到的最新值:

SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC LIMIT 1; 

(我取消了查詢10多分鐘後)

當沒有給定對象ID的值時(如果有結果,速度很快),此查詢非常慢。 如果我刪除它告訴我的極限幾乎是瞬間,有沒有結果:

SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC; 
... 
Time: 0.463 ms 

的解釋讓我發現,沒有限制的查詢使用索引,其中與limit 1查詢不使用索引:

慢查詢:

explain SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC limit 1; 
QUERY PLAN` 
---------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=0.00..2350.44 rows=1 width=126) 
-> Index Scan Backward using object_values_timestamp on object_values (cost=0.00..3995743.59 rows=1700 width=126) 
    Filter: (objectID = 53708)` 

快速查詢:

explain SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC; 
                QUERY PLAN 
-------------------------------------------------------------------------------------------------------------- 
Sort (cost=6540.86..6545.11 rows=1700 width=126) 
    Sort Key: timestamp 
    -> Index Scan using object_values_objectID on working_hours_t (cost=0.00..6449.65 rows=1700 width=126) 
     Index Cond: (objectID = 53708) 

該表包含44,884,559行和66,762個不同的objectID。
我在兩個字段上都有單獨的索引:timestampobjectID
我在表格上完成了vacuum analyze,並且我重新編制了表格。

此外慢速查詢變快時,我將限制設置爲3或更高:

explain SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC limit 3; 
                QUERY PLAN 
-------------------------------------------------------------------------------------------------------------------- 
Limit (cost=6471.62..6471.63 rows=3 width=126) 
    -> Sort (cost=6471.62..6475.87 rows=1700 width=126) 
     Sort Key: timestamp 
     -> Index Scan using object_values_objectID on object_values (cost=0.00..6449.65 rows=1700 width=126) 
       Index Cond: (objectID = 53708) 

總的來說,我認爲它與策劃者做出關於exectution成本錯誤的假設做,因此選擇了較慢的執行計劃。

這是真正的原因嗎?有沒有解決方案?

回答

23

您正遇到一個問題,我認爲這個問題涉及缺乏關於行關聯的統計信息。如果這是使用最新版本的Postgres,請考慮向pg-bugs報告以供參考。

我建議你計劃的解釋是:

  • limit 1使得Postgres的尋找一個單行,並在這樣做它假定你object_id是很常見,它會合理地顯示出來快速進行索引掃描。

    根據你給出的想法可能是它需要平均讀〜70行才能找到合適的行;它只是沒有意識到object_id和timestamp與它實際上將讀取大部分表的點相關。

  • limit 3,相比之下,使它認識到,這是不夠的罕見,因此它認真考慮(並最終...)從高到低的N與排序預期的1700行object_id你想要的,理由是這樣做可能會更便宜。

    例如,它可能知道這些行的分佈是這樣的,它們都被打包在磁盤上的同一區域。

  • limit子句意味着它將獲取1700,因此它直接在object_id上索引。

解決方案,順便說一句:上(object_id, timestamp)(object_id, timestamp desc)添加索引。

+0

對於'極限1'的情況你的意思是表掃描?你寫了索引掃描 – harmic

+0

@harmic:OP在那裏有一個索引掃描...不一定是整個表,但肯定比PG想象的要多得多。 –

+0

你是對的!我只讀到OP的文本,他說它沒有使用索引。但它選擇掃描時間戳索引;奇怪的選擇 – harmic

18

您可以通過向查詢添加不需要的ORDER BY子句來避免此問題。

SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp, objectID DESC limit 1; 
+1

哈!太棒了!完全修復它! – BrianC

+1

這個答案實際上有效,不像上面的答案和所有評論。 – mianos

+0

太棒了!只是提高我的查詢,並可以在運行時使用它。謝謝! –