如何在主流数据库中高效按自定义间隔查询时间序列数据无需预聚合
自定义间隔时间序列采样的数据库实现方案
方案选型说明
你需要的动态间隔采样、无需预聚合/重复存储数据的需求,主流时序数据库、分析型数据库都有原生支持,所有方案均依赖时间戳索引即可实现高效查询,不需要额外的预编码或文件结构改造。以下是开箱即用的实现方案:
1. ClickHouse(性能最优,优先推荐)
ClickHouse天生针对时序场景做了排序索引优化,时间戳设为主键即可完全适配内存缓存,支持动态调整采样间隔,TB级数据也能毫秒级返回结果。
按固定行数跳采(每n个点取1个)
对应你示例中skip_value=10的需求,查询示例:
SELECT ts, value FROM ( SELECT ts, value, ROW_NUMBER() OVER (ORDER BY ts ASC) AS row_num FROM ts_data WHERE ts > 1000 AND ts < 2000 ) t WHERE (row_num - 1) % 10 = 0 ORDER BY ts ASC
按时间区间取首个采样点(如每小时第一个点)
针对采集频率不稳定的场景,查询示例:
SELECT min(ts) AS sample_ts, argMin(value, ts) AS sample_value FROM ts_data WHERE ts > 1000 AND ts < 2000 -- 分组单位可动态调整,支持分钟、小时、天等任意粒度 GROUP BY toStartOfHour(toDateTime(ts)) ORDER BY sample_ts ASC
2. InfluxDB(专门时序数据库,语法最简)
InfluxDB是专为时序场景设计的数据库,原生提供采样函数,无需手写复杂逻辑:
固定行数跳采示例
start = 1000 stop = 2000 skip_count = 10 from(bucket: "你的存储桶名称") |> range(start: time(v: start), stop: time(v: stop)) |> filter(fn: (r) => r._measurement == "ts_data" and r._field == "value") // 每skip_count个点取第一个 |> sample(n: skip_count, pos: 0)
按时间区间取首个点示例
from(bucket: "你的存储桶名称") |> range(start: time(v: start), stop: time(v: stop)) |> filter(fn: (r) => r._measurement == "ts_data" and r._field == "value") // 每1小时取第一个点,时间粒度可动态调整 |> aggregateWindow(every: 1h, fn: first)
3. MongoDB(兼容现有技术栈,无需迁移)
如果你不想切换现有MongoDB技术栈,5.0以上版本支持窗口函数与时序集合,只要给ts字段建升序索引即可实现需求:
固定行数跳采示例
db.ts_data.aggregate([ // 过滤时间范围,命中ts索引 { $match: { ts: { $gt: 1000, $lt: 2000 } } }, { $sort: { ts: 1 } }, // 给每行分配行号 { $setWindowFields: { sortBy: { ts: 1 }, output: { row_num: { $documentNumber: {} } } }}, // 每10行取第一个 { $match: { $expr: { $eq: [ { $mod: [ { $subtract: [ "$row_num", 1 ] }, 10 ] }, 0 ] } } }, { $project: { ts: 1, value: 1, _id: 0 } } ])
按时间区间取首个点示例
db.ts_data.aggregate([ { $match: { ts: { $gt: 1000, $lt: 2000 } } }, { $sort: { ts: 1 } }, // 按小时截断分组,时间单位可动态调整 { $group: { _id: { $dateTrunc: { date: { $toDate: "$ts" }, unit: "hour" } }, sample_ts: { $first: "$ts" }, sample_value: { $first: "$value" } }}, { $sort: { sample_ts: 1 } } ])
以上所有方案均不需要预聚合生成rollup表、不需要重复存储数据,仅依赖时间戳索引即可完成高效查询,几十GB规模的数据在时间戳索引放入内存的前提下,查询延迟均可控制在百毫秒级别。
内容的提问来源于stack exchange,提问作者some bits flipped
相关产品推荐
相关产品推荐

