大佬们,请教一下数据读取

5 天前
 iamtuzi3333
小弟负责是后端内容的编写,现在系统有一批传感器,数据格式都是 json ,每个传感器每秒都有数据发送过来。我接收,然后写入文件,每天一个.json ,例如:传感器编号-日期-文件,这样的格式。文件中每行都是{}的数据,里面有时间戳,data ,例如{"time":12346574,"data":[1,2,3,4,5]},每一行都是这样的形式。文件夹目录有分层,每天都有一个日期对应的目录,里面就是当天的数据文件。数据同时存入到数据库 Mongo 中,单个节点,建了 time 字段的索引。现在查询历史数据量多的话感觉速度还是有点慢,依靠 time 字段找出时间范围的数据,取出每条数据的 data 元素;现在小弟想数据库只存储当前 3 天的数据,就是额外写一个脚本定时删除三天以前的数据,然后历史数据改为读取对应文件及日期的文件数据,这样读取历史数据是否可行,速度是否更快呢,后端用的 node ,他读取数据量量一大就容易内存栈,这个 data 字段元素有 200 个浮点数,一天能存 86400*200 多个数字,所以读取历史数据有时候读的时间范围大就容易崩,想请教大佬们怎么处理好一点。
1379 次点击
所在节点    程序员
26 条回复
skallz
5 天前
如果查询范围不大的话,可以考虑直接让前端拿对应文件的内容前端处理,让客户端分担服务端的性能压力,哈哈哈哈,前提是你的文件服务器和业务服务器不是同一个服务器,比如用的云服务商 oss 之类的
chihiro2014
5 天前
为什么感觉应该是使用 influxdb 之类的产品,而不是 mongo
xiaofsu
5 天前
最好的办法就是换个时序数据库。
daxin945
5 天前
如果是我的话可能会用 clickhouse 替换 mongo
MoYi123
5 天前
没必要, 数据库一般会用一些压缩算法, 肯定比你支持存 json 文件要省的.
数据库里用 partition table, 按日期分
内存溢出肯定是你代码有错, 86400*200 个 float 应该还不到 100MB.
timethinker
5 天前
mongodb 从 5.0 开始支持时间序列( Time Series ),可以提高查询速度。

https://www.mongodb.com/docs/manual/core/timeseries/timeseries-procedures/
sagaxu
5 天前
数据总量是多少,每次查询返回多少,有点儿慢是多慢,查询是怎么写的,这些都没讲清楚,不大好分析。
Oldletter
5 天前
MongoDB 支持 TTL 索引,允许自动删除超过指定时间的数据。你可以为 time 字段创建一个 TTL 索引来确保数据库中只保留 3 天的数据,这样就不需要手动写脚本来删除过期数据。

你的数据感觉不是特别大,所以建议你看看代码问题吧
iamtuzi3333
5 天前
@skallz 范围也大,会查询去年某一个月的所有数据,前端处理不太现实,现在文件跟业务都在一个服务器。
@chihiro2014 我之前看过这个,但是他对 json 格式数据不太友好,部署相对麻烦。
@xiaofsu 看了部分时序数据库,发现部分接口、迁移、数据格式不太方便。
@daxin945 我查查这个数据库看看效果。
iamtuzi3333
5 天前
@MoYi123 内存溢出是 node 的问题好像,我试过查询去年某一段时间的数据,他就查询内存栈溢出了。
@sagaxu 数据总量很多,每天 86400 条 json 存入,每次查询返回不定期,就是得根据前端传回的时间范围作为查询条件,有时候会查询去年某一段时间的数据,慢的时候主要是等待很久,数据库的每个集合的 timestamp 字段有做索引。查询代码如下:
// 获取 MongoDB 原生数据库连接
const db = mongoose.connection.db;
// 获取指定的集合
const collection = db.collection(collectionName);
// 构建查询条件
const query = {};
const timestampInt = parseInt(timestamp, 10);
query.timestamp = timestampInt;
// 查询数据
const result = await collection.find(query).toArray();
if (result.length <= 0) {
ctx.status = 200;
ctx.body = { message: 'no data', data: [] };
return;
}

@Oldletter 代码相对来说比较简单,就是传入集合名字,时间范围,就去对应的结合查询,查询代码如上,后端用的 node ,koa 框架,但是我发现 Mongo 的数据迁移不太方便,比如说我要把 a 服务器的某一个库的所有数据转移到 b 服务器的 Mongo 实例中,就不太方便了。
Nitsuya
5 天前
@daxin945 #4 +1
sagaxu
5 天前
前端查一个月的数据干嘛用?浏览器根本无法展示。显然要做好聚合,缩小数据规模。
aloxaf
5 天前
没用过 MongoDB ,不过这类时间序列数据查询的优化方向都是差不多的:
1. 提前按天、按小时聚合数据,根据查询范围来调整返回数据的精度。就像楼上说的,一个月的数据得上百万条了,前端要这么多数据干嘛。
2. 原始数据可以存的时候就按小时打包来存,没必要每秒生成一条记录。
3. 你这数据量也不大,但不知道 MongoDB 存这些数据效率如何,如果太占空间可能要考虑对旧数据降采样(你真的需要查询三年前某分钟内每秒的数据?)或者转冷存储。

不过还是推荐直接用数序数据库,不仅速度更快还节省空间,而且「优化花费的时间」未必比「迁移花费的时间」更少,除了 influxdb 外也可以看看 timescaledb ,对于有 sql 经验的人来说迁移真的方便)
iamtuzi3333
5 天前
@sagaxu 查询画图展示,长时间的我会额外查询宿友再处理,比如每十分钟提取一个最大值,汇聚所有的值返回。但是归根到底我还是要查询这些时间范围的数据。
@aloxaf 前端查询数据主要是展示,会有额外的需求,不过我还是要单独查询出这些范围的数据做进一步的加工。原始数据是传感器就固定每秒会有数据,传感器一多,每小时打包就不方便了,有时需要上半段,有时候需要下半段,每秒是最好的处理方法。数据会查询很久之前的,需要保持。时序数据库我还在找,发现挺多不怎么合适,总有一两项让我退步🤣
nivalxer
5 天前
场景比较类似,只不过我们这边传感器数据没有到每秒,一般大概 10 几秒到几分钟不等。
目前也是 Mongodb 的方案,按每个站点(一个站会有多个参数)一张表方式存储,每个小时会抽一条数据放小时表,统计报表再根据公司配置进行公司表级的存储。
Mongodb 需要考虑查出来的文档返回不能超过 16M ,虽然有一些配置可以绕过限制。目前感觉在数据量比较多,也根据查询条件(时间等)加了索引情况下,响应速度一般。
如果数据比较频繁并且需要偶尔查出来比较多的历史数据(多天、月、季度)还是看看其他的方案,目前我也想看看有没有除 MongoDb 外的其他更好的方案。
hd10180
5 天前
虽然我很菜,但我也做过类似的数据处理。
我的看法是要分析的数据不要存成数组,后期可能不方便做查询,data 的每个数值应该有个属性名。
假设[26, 80, ..]代表的是 [温度, 湿度, ...] 转成 temp: value, hum: value 的方式存储。可能你的情况跟我的不太一样,就当我没说。
另外每个传感器应该有 uuid 的吧,索引做成 uuid+time 不知道会不会好些?还可以考虑写个额外的程序对数据做分析,比如做小时维度的数据统计、月维度的统计等。
securityCoding
5 天前
时序数据库干的活不要硬来
yyt6801
5 天前
楼上都提到的时序数据库就是为了解决这种问题, 首先你要知道 每秒的那个 data:[]里面都代表什么东西;知道结构其他都好办了, 剩下的交给时序数据库解决
sagaxu
5 天前
@iamtuzi3333 “比如每十分钟提取一个最大值”,这个事情可以提前做好。我之前做过一个数据结构类似的项目,有分钟汇总,小时汇总,天汇总,都是提前生成缓存好,当日数据还会存一份在内存里加速访问。一般查询都有个特点,时间段跨度越大,越不关心局部数据,缓存好的汇总表能极大提高查询速度。

一次查大量数据,只能在后台定时任务里跑,不能由前端触发查询,否则任何数据库都无法满足。数据量量一大,即使 nodejs 直接读文件解析,不经过 db ,也会消耗很大资源。
VchentozV
5 天前
@skallz 我一般就是这么做的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1101255

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX