如何优化在 SQLite 中创建直方图箱?

问题描述

我想对整数进行分组,例如纪元时间值,放入相同大小的箱中,例如5、在 sqlite 中。

即转这个:

geolocation table:
+-------+
| time  |
+-------+
| 0     |
| 0     |
| 0     |
| ...   |
| 46801 |
| 46801 |
| ...   |
| 46802 |
| ...   |
+-------+

进入这个:

query result:
+-------+-------+
| bin   | count |
+-------+-------+
| 0     | 134   |
| 46800 | 400   |
| 46805 | 223   |
| 46810 | 161   |
| ...   | ...   |
+-------+-------+

我可以使用以下查询来实现:

select bin,count(*) as count from (
    select cast(time/5.00 as int)*5 as bin
    from geolocation
    order by time
)
group by 1;

但是,当 geolocation 表有 400 万行时,执行此查询大约需要 1.3 秒。内部查询本身非常快,所以我假设大部分时间都在执行外部查询

假设time表中的geolocation字段被索引,有没有办法优化这个查询

因为内部查询已经返回排序值,所以外部查询重复二分搜索不同值并获取每个不同值的计数不是很简单吗? (我不确定 group by 在幕后如何工作)。使用这种方法应该需要 O(log n) 复杂度。

解决方法

... 因为内部查询已经返回排序值,不是吗 外部查询直接重复二分查找 不同的值并获取每个不同值的计数?

子查询中的 ORDER BY 子句是无用的。
不保证外部查询会按特定顺序处理子查询返回的行。

就您而言,您可以将代码简化为:

SELECT time/5*5 AS bin,COUNT(*) AS count 
FROM geolocation
GROUP BY bin;

假设time的数据类型为INTEGER,表达式:

cast(time/5.00 as int)*5

可以写成:

time/5*5

因为当两个操作数都是整数时,SQLite 执行整数除法。

或者,您可以尝试使用 COUNT(*) 窗口函数:

SELECT DISTINCT time/5*5 AS bin,COUNT(*) OVER (PARTITION BY time/5*5) AS count 
FROM geolocation;