2015-12-02 124 views
0

我想得到一个温度计的温度读数给定表的平均温度,行结构:thermometer_id, timestamp (float, julian days), value (float)加上timestamp的升序索引。如何制作简单的GROUP BY使用索引?

要获得全天5天前,我使用这个查询:

SELECT 
    ROUND(AVG(value), 2), -- average temperature 
    COUNT(*)    -- count of readings 
FROM reads 
WHERE 
    timestamp >= (julianday(date('now')) - 5) -- between 5 days 
    AND 
    timestamp < (julianday(date('now')) - 4) -- ...and 4 days ago 
GROUP BY CAST(timestamp * 24 as int)   -- make hours from floats, group by hours 

它它工作得很好,但它的工作原理很慢,一个9MB的数据库,行35.5,这需要超过半秒钟才能完成,这很困难,应该不会超过几十毫秒。它不是很快的硬件(不是SSD),但是我正准备在树莓派上使用它,相对比较慢+每天的工作量会增加80k行。

Explain解释了原因:

“使用温度B-树GROUP BY”

我已经尝试添加dayhour列使用索引只是为了快速访问的缘故,不过,组由于没有使用任何指标。

如何调整此查询或数据库以使此查询更快?

+1

演员和乘员可能会在使用索引进行分组时失败。如果你有最新版本的SQLite(3.9.2),那么你可以尝试[在group-by表达式上创建一个索引](http://sqlite.org/expridx.html) –

+0

不幸的是,我有sqlite 3.7.14与python 2.7.3。我使用'set hour = CAST(timestamp * 24 as int)'创建了'hour'列,但它同样很慢,查询规划器仍然使用“使用临时b树作为group by”。 –

回答

0

正如@上校-32人所评论的那样,问题出现在GROUP BY CAST(timestamp * 24 as int)上。这样的分组完全可以省略索引,因此查询时间很慢。当我使用hour列进行时间比较和分组时,查询立即完成。

1

如果使用索引来优化GROUP BY,则不能再优化timestamp搜索(除非使用旧版SQLite可能没有的skip-scan optimization)。并且通过全部reads,仅仅因为一个不匹配的时间戳而丢掉大部分行,将不会有效。

如果SQLite不自动做正确的事,即使在运行ANALYZE后,你可以尝试迫使它使用特定的指标:

CREATE INDEX rhv ON reads(hour, value); 
SELECT ... FROM reads INDEXED BY rhv WHERE timestamp ... GROUP BY hour; 

但这不太可能导致查询计划,实际上更快。