JYe*_*ton 14 mysql database-design partitioning
背景
我有一个由大约 2000 个传感器组成的网络,每个传感器都有大约 100 个数据点,我们每隔 10 分钟收集一次。这些数据点通常是 int 值,但有些是字符串和浮点数。这些数据应该存储 90 天,如果可能的话,更多并且仍然有效。
数据库设计
当最初负责这个项目时,我编写了一个 C# 应用程序,为每个传感器编写逗号分隔的文件。当时没有那么多,当有人想查看趋势时,我们会在 Excel 中打开 csv 并根据需要绘制图表。
事情发展了,我们切换到了 MySQL 数据库。我为每个传感器创建了一个表格(是的,我知道,很多表格!);它运行良好,但有一些限制。有这么多表,显然不可能编写一个查询,在查找特定值时会在所有传感器中查找数据。
对于下一个版本,我切换到 Microsoft SQL Server Express,并将所有传感器数据放入一个大表中。这也有效,并让我们进行查询以在所有感兴趣的传感器中查找值。但是,我遇到了 Express 版本的 10GB 限制,并决定切换回 MySQL 而不是投资 SQL Server Standard。
问题
我对 MySQL 的性能和可扩展性很满意,但我不确定坚持所有数据在一个表中的方法是否最好。单个表中的 10GB 似乎要求不同的设计。我应该提到的是,仍然需要查询数据以绘制图形,而且我担心绘制图形的查询会出现性能问题,例如,一个传感器在整个 90 天内的温度数据。(换句话说,图形应该是快速生成的,而无需等待 SQL 对成堆的数据进行排序以隔离感兴趣的传感器。)
我应该以某种方式拆分此表以提高性能吗?或者有这么大的桌子也不是什么稀奇事?
我在 Sensor ID 和 Timestamp 列上有索引,这几乎是任何查询的定义边界。(即从时间 A 到时间 B 获取传感器 X 的数据)。
我已经阅读了一些关于分片和分区的内容,但在这种情况下不觉得这些是合适的。
编辑:
根据到目前为止的评论和答案,一些额外的信息可能会有所帮助:
非无限期存储:目前我不存储超过 90 天的数据。每天,我都会运行一个查询来删除超过 90 天的数据。如果将来它变得重要,我会存储更多,但现在已经足够了。这有助于控制大小和高性能(呃)。
引擎类型:最初的 MySQL 实现使用了 MyISAM。这次为新实现(一个数据表而不是多个)创建表时,他们默认为 InnoDB。我不相信我对其中一个有要求。
归一化:当然还有除了数据采集表之外的其他表。这些支持表存储诸如传感器的网络信息、用户的登录信息等内容。没有太多需要规范化的内容(据我所知)。数据表有这么多列的原因是每个传感器有这么多变量。(多个温度、光照水平、气压等)对我来说标准化意味着没有冗余数据或重复组。(至少对于 1NF。)对于给定的传感器,在特定时间存储所有值需要一行数据,并且那里不涉及 1:N 关系(我看到)。
我可以在功能上分解表格,制作(例如)一张表中所有与温度相关的值,以及另一张表中所有与气压相关的值。虽然这可能会提高仅进行温度查询的效率,但我仍然必须一次插入所有数据。尽管如此,对于 SELECT 操作来说,效率提升可能是值得的。显然,我最好根据用户请求数据的频率垂直拆分表格。也许这就是我应该做的。我想在问我的问题时,我想确认这样做是值得的。
编辑2:
数据使用:最终大部分数据从未被查看或需要,因为我们通常只关注有问题的项目。但是在尝试发现问题时,我们使用各种工具来搜索数据并确定要放大的项目。
例如,我们注意到内存使用值(客户特定的专有软件程序)与重启/崩溃之间存在相关性。我收集的数据点之一与此内存使用量有关,并且我能够查看历史数据以显示超过特定内存使用量后设备变得不稳定。今天,对于运行此软件的设备子集,我检查此值并在它过高时发出重新启动命令。在发现这一点之前,我认为收集这些数据没有价值。
出于这个原因,我一直坚持收集和存储大约 100 个数据点,即使该值有问题。但是在正常的日常使用中,用户通常会检查其中的十几个参数。如果用户对特定的地理区域感兴趣,他可能(使用软件)为几十个传感器生成图表或数据电子表格。查看带有两到三个绘图线的 30 天图表,显示温度、气压和光照水平等内容的情况并不少见。这样做会运行一个类似于这样的查询:
SELECT sensor_id, location, data_timestamp, temp1, air1, light1
FROM data
WHERE data_timestamp >= '2012-02-01'
AND sensor_id IN (1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
(在最初的 MySQL 版本中,每个传感器都有自己的表,将发出三个单独的查询,但结果在软件中合并以创建图形。)
由于该data
表包含如此多的行(约 1000 万),尽管在id
和上有索引data_timestamp
,但性能明显低于多表场景(9 秒内返回 4500 行,而不是本示例中的不到一秒)。在多表模式中,找到满足特定标准的传感器的能力几乎为零,因此移动到单个表的原因。
这种类型的查询可以由多个用户快速连续完成,因为他们选择不同的数据组并比较每个结果的图形。每个图表或电子表格等待近 10 秒可能会非常令人沮丧。
数据在 90 天后被丢弃。它可以存档,但目前不是必需的。
希望这些信息有助于更充分地展示数据在收集和存储后如何使用。
您应该出于一个重要原因考虑对表进行分区。
你在一张大表上的所有索引,即使只有一个索引,在执行 INSERT、UPDATE 和 DELETE 时,可能会产生大量的 CPU 负载和磁盘 I/O,只是为了执行索引维护。
我早在 2011 年 10 月 7 日写了一篇关于为什么表分区会有很大帮助的帖子。这是我上一篇文章的摘录:
数据的分区应该用于对逻辑上和内聚性在同一类中的数据进行分组。只要数据正确分组,搜索每个分区的性能就不必是主要考虑因素。一旦实现了逻辑分区,就可以专注于搜索时间。如果您只是仅按 id 分隔数据,则可能永远无法访问多行数据以进行读取或写入。现在,这应该是一个主要考虑因素:找到所有最常访问的 id 并以此进行分区。所有不常访问的 id 都应该驻留在一个大的存档表中,该表仍然可以通过索引查找来访问“一次次”查询。
您可以稍后阅读我的整篇文章。
为了切入正题,您需要研究并找出 10GB 表中很少使用的数据。如果您需要针对历史性质的即席查询,则应将该数据放置在易于访问的存档表中。从 10GB 迁移该存档,然后OPTIMIZE TABLE
在 10GB 表上迁移,可以导致运行 SELECT、INSERT、UPDATE 和 DELETE 的工作集更快。甚至 DDL 在 2GB 工作集上的运行速度也比 10GB 表快。
需要考虑的两点
这是我关于如何使用它的两个帖子:
这是我在有很多列的表格上发表的额外帖子
有趣...如果所有传感器产生相同类型的数据,将它们全部放在同一个表中确实有意义,但是有了这么多数据,我可以理解为什么您会担心性能。
90 天是您制作图表的常用时间吗?如果是这样,您可以有两个表:主传感器数据表,存储从 90 天(如果您想要一些松弛的话可以多一点)直到今天的数据,以及比这更旧的所有内容都在存档表中。这可以帮助减少开始生成报告的表的大小,并且希望您的 10 GB 数据中的大部分将在存档表中,而不是在主表中。归档作业可以安排为每晚运行。
也许还可以考虑构建一个单独的报告数据库,将数据存储在更适合从中生成报告的结构中(设计为更紧密地匹配您查询的内容的表,并且可能预先计算和聚合值,否则需要很长时间才能生成)生成,如果可能的话),并定期(例如每晚)从主数据库重新填充它。当然,如果您需要根据最新数据生成报告,这可能不太好用。