我希望获得温度读数的给定表的每小时平均温度,行结构:thermometer_id, timestamp (float, julian days), value (float)
加上timestamp
的升序索引。
要在4天前获得全天,我正在使用此查询:
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的数据库,355k行,完成需要超过半秒,这是令人困惑的长,它不应该超过几十毫秒。它不是很快的硬件(不是ssd),但我准备在树莓派上使用它,相比之下相当慢,它每天可以获得8万多行。
Explain
解释原因:
“使用TEMP B-TREE for GROUP BY”
为了快速访问,我尝试在索引中添加day
和hour
列,但仍然,group by没有使用任何索引。
如何调整此查询或数据库以使此查询更快?
答案 0 :(得分: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;
但这不太可能导致查询计划实际上更快。
答案 1 :(得分:0)
正如@ Colonel-three-two评论的那样,问题在于=IFERROR(INDEX($8:$8,MATCH(A13,$5:$5,0)),"")
上的强制转换和乘法。这种分组将完全省略索引,因此查询时间较慢。当我使用GROUP BY CAST(timestamp * 24 as int)
列进行时间比较和分组时,查询立即完成。