我有以下MYSQL表:
measuredata:
- ID (bigint)
- timestamp
- entityid
- value (double)
该表包含>10 亿个条目。我希望能够可视化任何时间窗口。时间窗口的大小可以是"一天"到"多年"。DB中几乎每分钟都有测量值。
因此,时间窗口的条目数可能大不相同。比如说从几百到几千或几百万。
这些值可以在网页上的图形图表中可视化。
如果图表是 - 比方说 - 800px 宽,如果时间窗口很大,从数据库中获取数千行是没有意义的。无论如何,我不能在此图表上显示超过 800 个值。
那么,有没有办法直接在数据库端减少结果集呢? 我知道"平均值"和"总和"等是聚合函数。但是我怎样才能从一个大的时间窗口聚合 100k 行,比如说 800 行的最后一行?
只是获取这 100k 行并让图表发挥魔术并不是首选。传输大小是这不是一个选项的原因之一。
DB端没有我可以使用的东西吗? 像 avg(( 这样的东西将 X 行缩小到 Y 平均行? 还是跳过每 #th 行将 X 缩小到 Y 的简单魔法?
更新: 虽然我现在正在使用MySQL,但我并没有被这个束缚。如果PostgreSQL f.i.提供了一个可以解决这个问题的功能,我愿意切换DB。
更新2: 我也许找到了一个可能的解决方案:https://mike.depalatis.net/blog/postgres-time-series-database.html 请参阅"数据汇总"一节。
关键不是使用 unixtimestamp,而是使用日期并"截断"它,平均值并按截断日期分组。可以为我工作,但需要重新设计我的表结构。嗯。。。也许还有更多...还在研究...
更新3: 受到更新 2 的启发,我想出了这个查询:
SELECT (`timestamp` - (`timestamp` % 86400)) as aggtimestamp, `entity`, `value` FROM `measuredata` WHERE `entity` = 38 AND timestamp > UNIX_TIMESTAMP('2019-01-25') group by aggtimestamp
有效,但我的 DB/索引/结构似乎并没有真正为此进行优化:去年的查询花了 ~75 秒(慢测试机器(,但最终每天只得到一个值。这可以与 avg(value
( 结合使用,但这进一步增加了查询时间...(~82秒(。我将看看是否有可能进一步优化这一点。但是我现在知道了"缩减采样"数据的工作原理,尤其是聚合与"分组依据"相结合。
可能没有有效的方法来做到这一点。 但是,如果需要,您可以将行分成大小相等的组,然后从每个组中获取第一行。 这是一种方法:
select md.*
from (select md.*,
row_number() over (partition by tile order by timestamp) as seqnum
from (select md.*, ntile(800) over (order by timestamp) as tile
from measuredata md
where . . . -- your filtering conditions here
) md
) md
where seqnum = 1;