如何使简单的 GROUP BY 使用索引?
How to make simple GROUP BY use index?
我想通过温度计的温度读数获取给定 table 的每小时平均温度,行结构: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)上这样做,但我正准备在 raspberry pi 上使用它,相比之下相当慢 + 它每天的工作将增加 80k 行。
Explain
解释原因:
"USE TEMP B-TREE FOR GROUP BY"
我已经尝试添加 day
和 hour
列的索引只是为了快速访问,但是,group by 仍然没有使用任何索引。
如何调整此查询或数据库以加快此查询速度?
如果使用索引来优化 GROUP BY,则无法再优化 timestamp
搜索(除非使用 skip-scan optimization,您的旧 SQLite 可能没有)。并且遍历 reads
中的 所有 行,只是因为时间戳不匹配而将其中的大部分丢弃,效率不高。
如果 SQLite 没有自动执行正确的操作,即使在 运行 ANALYZE 之后,您可以尝试强制它使用特定索引:
CREATE INDEX rhv ON reads(hour, value);
SELECT ... FROM reads INDEXED BY rhv WHERE timestamp ... GROUP BY hour;
但这不太可能产生实际上更快的查询计划。
正如@colonel-thirty-two 评论的那样,问题出在 GROUP BY CAST(timestamp * 24 as int)
上的转换和乘法。这样的分组将完全忽略索引,因此查询时间很慢。当我使用 hour
列进行时间比较和分组时,查询立即完成。
我想通过温度计的温度读数获取给定 table 的每小时平均温度,行结构: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)上这样做,但我正准备在 raspberry pi 上使用它,相比之下相当慢 + 它每天的工作将增加 80k 行。
Explain
解释原因:
"USE TEMP B-TREE FOR GROUP BY"
我已经尝试添加 day
和 hour
列的索引只是为了快速访问,但是,group by 仍然没有使用任何索引。
如何调整此查询或数据库以加快此查询速度?
如果使用索引来优化 GROUP BY,则无法再优化 timestamp
搜索(除非使用 skip-scan optimization,您的旧 SQLite 可能没有)。并且遍历 reads
中的 所有 行,只是因为时间戳不匹配而将其中的大部分丢弃,效率不高。
如果 SQLite 没有自动执行正确的操作,即使在 运行 ANALYZE 之后,您可以尝试强制它使用特定索引:
CREATE INDEX rhv ON reads(hour, value);
SELECT ... FROM reads INDEXED BY rhv WHERE timestamp ... GROUP BY hour;
但这不太可能产生实际上更快的查询计划。
正如@colonel-thirty-two 评论的那样,问题出在 GROUP BY CAST(timestamp * 24 as int)
上的转换和乘法。这样的分组将完全忽略索引,因此查询时间很慢。当我使用 hour
列进行时间比较和分组时,查询立即完成。