2014-01-27 171 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

太棒了!只是提高我的查询,并可以在运行时使用它。谢谢! –