有效存储时间序列数据:mySQL或平面文件?许多表(或文件)或具有WHERE条件的查询?

use*_*659 13 mysql time-series

什么是存储数千个时间序列数据(但可能很快就会成为数百万个)真实世界硬件传感器的最佳方法?传感器本身是不同的,有些只捕获一个变量,有些只有十几个.我需要每小时存储这些值,并且我不想删除早于x的数据,即数据将继续增长.

目前,我使用mySQL数据库来存储这些时间序列(它还提供了一个Web前端,为每个传感器显示了漂亮的时间序列图).每个传感器都有一个表,现在总共大约11000个.每个表都有一个类似"timestamp,value1,[value2] ..."的布局.

数据库的主要任务是更多选择(每次sombebody查看图表)而不是插入/更新(每小时一次).显示图形的选择查询只是一个"SELECT*FROM $sensor_idORDER BY timestamp",因此从我的select语句中获取信息非常简单/高效.

但是,拥有那么多表在备份数据库时已经出现了一些问题,因为我遇到了LOCK限制(例如mysqldump:Got error:23:打开文件时资源不足'./database/table_xyz.MYD'(错误代码:24) )当使用LOCK TABLES时).我可以解决这个错误,但很明显这让我思考......

那么,真正的问题,分解为子问题:

  • 我为每个传感器配备一张桌子的方法有多糟糕?如果不是几千张桌子,我就有几百万(我可能不得不在不久的将来处理那么多传感器)怎么办?
  • 将所有传感器的数据存储在一个组合表中,并使用额外的列来保存sensor_id是一种更好的方法,因为它可能会大大减慢我的select语句(SELECT*来自all_sensorsWHERE sensor_id='$ sensor_id')?请记住,不同的传感器测量不同的东西,所以如果我每个传感器都有自己的表,那么这个表会有几十列,而不是一个到几个.
  • 我还考虑过将时间序列数据存储在mySQL中,而不是存储在平面(CSV)文件中.我用于前端(dygraphs)的图形库可以很好地处理CSV文件(加上它可以让我选择让这些文件可供下载,这将是一个奖励,但目前不是一个要求).我仍然需要数据库用于其他前端相关的东西,但这意味着有几十个表而不是11000个(如果我们添加更多传感器,甚至更多).
  • 如果我为每个表创建一个文件,那么我最终可能会遇到文件系统限制(这是一个ext3分区,所以每个目录限制有~32k文件).所以这里也适用同样的问题:我应该将它存储在一个包含所有传感器数据的大文件中吗?这可能会减慢我的读取速度,因为图形化的库将需要在每次有人查看图形时将更大,更大的文件读入内存?

你会怎么做?

谢谢!

N.B*_*.B. 7

要回答这个问题,我们首先要分析你所面临的真正问题.

真正的问题是编写和检索数据的最有效组合.

让我们回顾一下你的结论:

  • 成千上万的表 - 嗯,这违反了数据库的目的,并使其更难以使用.你也什么也得不到.仍然涉及磁盘搜索,这次使用了许多文件描述符.您还必须知道表名,并且有数千个.提取数据也是很困难的,这就是数据库的用途 - 以一种您可以轻松交叉引用记录的方式构建数据.成千上万的表 - 从perf不高效.观点看法.从使用的角度来看效率不高.糟糕的选择.

  • 一个csv文件 - 如果你需要一次全部内容,它可能非常适合获取数据.但是,对于操纵或转换数据来说远远不够好.鉴于您依赖于特定布局 - 在写入CSV时必须格外小心.如果这种情况增长到成千上万的CSV文件,那么你并没有帮忙.你删除了SQL的所有开销(这不是那么大)但你没有做任何事情来检索数据集的部分.您在获取历史数据或交叉引用任何内容时也会遇到问题.糟糕的选择.

理想的情况是能够以有效和快速的方式访问数据集的任何部分,而无需任何结构更改.

这正是我们使用关系数据库的原因,也是为什么我们将具有大量RAM的整个服务器专用于这些数据库的原因.

在您的情况下,您正在使用MyISAM表(.MYD文件扩展名).这是一种旧的存储格式,适用于当天使用的低端硬件.但是现在,我们拥有出色而快速的计算机.这就是我们使用InnoDB并允许它使用大量RAM以降低I/O成本的原因.调用控制它的问题innodb_buffer_pool_size- 谷歌搜索将产生有意义的结果.

要回答这个问题 - 一个有效,可满足的解决方案是使用一个存储传感器信息的表(id,标题,描述)和另一个存储传感器读数的表.您可以分配足够的RAM或足够快的存储空间(SSD).表格如下所示:

CREATE TABLE sensors ( 
    id int unsigned not null auto_increment,
    sensor_title varchar(255) not null,
    description varchar(255) not null,
    date_created datetime,
    PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;

CREATE TABLE sensor_readings (
    id int unsigned not null auto_increment,
    sensor_id int unsigned not null,
    date_created datetime,
    reading_value varchar(255), -- note: this column's value might vary, I do not know what data type you need to hold value(s)
    PRIMARY KEY(id),
    FOREIGN KEY (sensor_id) REFERENCES sensors (id) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
Run Code Online (Sandbox Code Playgroud)

默认情况下,InnoDB使用一个平面文件进行整个数据库/安装.这缓解了超出OS /文件系统的文件描述符限制的问题.如果要分配5-6演出的RAM来保存内存中的工作数据,那么几个甚至数千万条记录应该不会成为问题 - 这样可以快速访问数据.

如果我要设计这样一个系统,这是我要做的第一个方法(个人).从那里开始,根据您对该信息的需求,可以轻松调整.

  • 我先创建一个名为“ categories”的表,然后创建一个带有可为空的“ additional_variable_column”的“ sensors2categories(sensor_id,category_id,additional_variable_column)”表。现在,您可以将传感器添加到任意多个类别中,并且可以添加类别(或删除它们)而无需更改任何表格。可以以多种方式查询这种模型,并且维护非常简单。 (2认同)