MySQL:将大表拆分为分区或单独的表?

标签 mysql database partitioning large-data

我有一个包含 20 多个表的 MySQL 数据库,但其中一个表非常大,因为它从不同的传感器收集测量数据。它的磁盘大小约为 145 GB,包含超过 10 亿条记录。所有这些数据也被复制到另一个 MySQL 服务器。

我想将数据分成更小的“碎片”,所以我的问题是以下哪种解决方案更好。我会使用记录的“时间戳”来按年划分数据。几乎所有在此表上执行的 SELECT 查询都在查询的“where”部分包含“timestamp”字段。

所以以下是我无法决定的解决方案:

  1. 使用 MySQL 分区并按年份划分数据(例如分区 1 - 2010,分区 2 - 2011 等)
  2. 创建单独的表格并按年份划分数据(例如 measuring_2010、measuring_2011 等表格)

还有我不知道的任何其他(更新的)可能选项吗?

我知道在第一种情况下 MySQL 本身会从“分片”获取数据,而在第二种情况下我必须为它编写一种包装器并自己完成。对于第二种情况,是否有任何其他方法可以使所有单独的表被视为“一个大表”以从中获取数据?

我知道这个问题过去已经被问过,但也许有人提出了一些新的解决方案(我不知道)或者最佳实践解决方案现在已经改变了。 :)

非常感谢您的帮助。

编辑:

架构与此类似:

device_id (INT)
timestamp (DATETIME)
sensor_1_temp (FLOAT)
sensor_2_temp (FLOAT)
etc. (30 more for instance)

所有传感器温度每分钟一次写入同一时刻。请注意,大约有 30 个不同的传感器测量值连续写入。此数据主要用于显示图表和其他一些统计目的。

最佳答案

好吧,如果您希望得到一个新答案,那意味着您可能已经阅读了我的答案,而且我听起来像是一张破唱片。参见 Partitioning blog对于分区可以帮助提高性能的少数用例。你的情况听起来像这 4 种情况中的任何一种。

收缩 device_idINT为4个字节;你真的有数百万台设备吗? TINYINT UNSIGNED 为 1 个字节,范围为 0..255。 SMALLINT UNSIGNED 是 2 个字节,范围是 0..64K。这会使表格缩小一点。

如果您真正的问题是关于如何管理如此多的数据,那么让我们“跳出框框思考”。继续阅读。

绘制图表...您绘制的日期范围是什么?

  • “最后”小时/天/周/月/年?
  • 任意小时/天/周/月/年?
  • 任意范围,不受日/周/月/年的限制?

你在画什么?

  • 一天的平均值?
  • 一天中的最大/分钟?
  • 一天或一周或其他什么的烛台(等)?

无论哪种情况,您都应该构建(并逐步维护)一个包含数据的汇总表。一行将包含一个小时的摘要信息。我建议

CREATE TABLE Summary (
    device_id SMALLINT UNSIGNED NOT NULL,
    sensor_id TINYINT UNSIGNED NOT NULL,
    hr TIMESTAMP NOT NULL,
    avg_val FLOAT NOT NULL,
    min_val FLOAT NOT NULL,
    max_val FLOAT NOT NULL
    PRIMARY KEY (device_id, sensor_id, hr)
) ENGINE=InnoDB;

一个摘要表可能是 9GB(对于当前数据量)。

SELECT hr,
       avg_val,
       min_val,
       max_val
    FROM Summary
    WHERE device_id = ?
      AND sensor_id = ?
      AND hr >= ?
      AND hr  < ? + INTERVAL 20 DAY;

将为您提供 480 小时的 hi/lo/avg 值;够作图吗?从汇总表中抓取 480 行比从原始数据表中抓取 60*480 行要快很多。

获取一年的类似数据可能会使图形包窒息,因此可能值得构建摘要的摘要 - 解决一天的问题。大约为 0.4GB。

有几种不同的方法来构建汇总表;我们可以在你思考它的美丽并阅读之后讨论它 Summary tables blog .最好的方法可能是收集一小时的数据,然后扩充摘要表。这有点像讨论的触发器 my Staging table blog .

而且,如果您有每小时的摘要,您真的需要每分钟的数据吗?考虑把它扔掉。或者,也许是一个月后的数据。这导致使用分区,但只是为了删除旧数据的好处,如 Partitioning blog 的“案例 1”中所讨论的那样.也就是说,您将每天进行分区,每晚使用 DROPREORGANIZE 来移动“Fact”表的时间。这将导致减少 145GB 的占用空间,但不会丢失太多数据。新足迹:约 12GB(每小时摘要 + 过去 30 天的每分钟详细信息)

附注:Summary Table blog展示了如何获得标准偏差。

关于MySQL:将大表拆分为分区或单独的表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46317100/

相关文章:

mysql - 与查询没有分区的相同数据相比,如果我一次在 mysql 中查询多个分区,是否存在任何性能问题?

C# 单元测试 - 生成模拟 DataContexts/LINQ -> SQL 类

php - 在 php 中只命中一次数据库连接

linux - 在实时挂载系统上调整根分区大小的解决方案

php - 检查数据库中的特定条目

java - 如何使用房间数据库从 LiveData 列表中检索用户以显示在 Spinner 中

for-loop - 有没有办法控制 OpenMP parallel_for 构造的分区?

php - 在 $row 中提取特定记录

php - 帮我为 iou Web 应用程序设计数据库架构

php - Laravel 显示与我的数据库不同的日期