2015-12-02 65 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; 

但這不太可能導致查詢計劃,實際上更快。