【问题标题】:Need correct database structure to reduce the size需要正确的数据库结构来减小大小
【发布时间】:2012-11-24 20:47:41
【问题描述】:

我想正确设计我的数据库。也许有人可以帮助我。

我有一个设备,它每 3 秒将大约 100 个键/值写入一个表。 有人建议这样存储:

^ 时间戳 ^ key1 ^ key2 ^ [...] ^ key150 ^

| 2012 年 12 月 6 日 |空 | 2243466 | [...] |空^

但我认为那是完全错误的,不是动态的。因为我可以有很多空值。 所以我尽力做到最好,并按照我在学校学到的方式设计它: http://ondras.zarovi.cz/sql/demo/?keyword=tempidi

这是我为每个值写入时间戳的问题,这意味着在 100 个值内它总是相同并产生大量数据。

有人能给我提示如何减小数据库大小吗?我的 ERM 基本正确吗?

【问题讨论】:

  • 您是否关心将相同的时间戳写入 100 行所占用的磁盘空间?
  • 是的。我的计算是:100 个值 * 16bytes * 24 (h) * 60(min) * 60(s) * 30 (month) = 3.8GB /month
  • 建议以这种方式存储的人不应该推荐数据库模型。
  • @YannicDoNotText 下面的答案详细说明了一个好的模型。您提供的模型具有应转换为行的列。

标签: mysql sql database-design entity-relationship


【解决方案1】:

我不会太担心数据库的大小。更大的问题是维护和灵活性。

这就是我要做的。首先,使用您的设备可以编写的可能的键定义并填写此表:

tblDataKey
(
    ID int primary key (auto-increment - not sure how mysql does this)
    Name varchar(32)
)

接下来定义一个“数据事件”表:

tblEvent
(
    ID int primary key (auto-inc)
    TimeStamp
    ...anything else you need - device ID's? ...
)

然后将事件与键及其值匹配:

tblEventData
{
    EventID INT FK-to-tblEvent
    KeyID INT FK-to-tblDataKey
    DataValue varchar(???)
)

现在,无论您的数据进入多少秒,您都会在 tblEvent 中创建一个条目,并根据需要在 tblEventData 中创建多个带有键值的条目。并非每个事件都需要每个键,您可以在未来扩展键的数量。

这真的很出色,因为没有浪费空间,您可以轻松地使用特定的数据键和值对 evnet 进行查询。当您需要生成“类似交叉表”的事件和数据项表时,这种结构就会失败。你必须决定这是否有问题。

【讨论】:

【解决方案2】:

如果您必须在 MySQL 中实现键值对存储,那么让它比这更复杂没有任何意义。

create table key_value_store (
  run_time datetime not null,
  key_name varchar(15) not null,
  key_value varchar(15) not null,
  primary key (run_time, key_name)
);

如果您的键和值的平均长度都是 10 字节,那么您每月可以查看大约 8600 万行和 2.5GB,并且您不需要任何连接。如果所有值(列 key_value)都是整数或浮点数,则可以更改数据类型并进一步减少空间。

在 SQL 中实现键值存储的主要问题之一是,除非所有值都是相同的数据类型,否则您必须对所有值使用类似 varchar(n) 的东西。你失去了类型安全和声明性约束。 (您无法检查 key3 的值在 1 到 15 之间,而 key7 的值在 0 到 3 之间。)


这可行吗?

这种结构(称为“EAV”--Google 认为)是一种众所周知的表格设计反模式。部分问题在于您实际上是将列存储为行。 (您将列名存储在 key_value_store.key_name 中。)如果您曾经必须以普通表的格式写出数据,您会发现三件事。

  1. 很难编写查询以输出正确的格式。
  2. 运行需要很长时间。如果您必须编写数百列,它可能永远无法完成。
  3. 您会希望拥有更快的硬件。很多、很多更快的硬件。

我在寻找什么

  • 将键分组到逻辑表中的机会。这与第一个设计有关,它可能不适用于您。听起来您的应用程序基本上是在存储一个日志文件,而您不知道每次运行时哪些键会有值。
  • 减少行数的机会。我会问,“我们能不能少写点?”因此,我会考虑每 5 或 6 秒而不是每 3 秒写入一次数据库,假设这意味着我正在写入更少的行。 (真正的目标是更少的行,而不是更少的写入。)
  • 正确的平台。 PostgreSQL 9.2 可能是一个更好的选择。 9.2 版具有仅索引扫描,并且具有实现键值存储的 hstore 模块。

先测试再做决定

如果我是你的话,我会在 MySQL 和 PostgreSQL 中构建这个表。我会用大约一百万行随机数据加载每个。然后我会尝试一些查询和报告。 (报告很重要。)衡量绩效。将负载增加到 1000 万行,重新调整服务器和 dbms,然后再次运行相同的查询和报告。再次测量。

重复 1 亿行。当你有信心时退出。预计所有这些都需要几天时间。

【讨论】:

  • @YannicDoNotText:2.5GB。我打开了两个电子表格,并用 alt-tab 键插入了错误的中间。按每分钟 20 次写入计算;每次写入 20*100 (2000) 行;每天 2,880,000 行;每月 86,400,000 行;每行 28 个字节;每月 2,419,200,000 字节。这是很多行。
  • 是的。我知道。但我必须这样做。这是针对具有 3 个月数据历史的监控项目...您认为这可能吗?使用建议的 ERM?第一个单行 100 列的建议是错误的,不是吗?
  • 第一个建议不是很好。一方面,MySQL 不会在一个页面上容纳很多行,因此会有很多 的磁盘活动。我将编辑我的答案以包含更多想法。
  • 感谢您的更新!它对我有很大帮助。上面我写道,我需要存储来自泵的更改参数(约 100 个)。我的项目负责人告诉我,我们需要每 3 秒存储一次。这使得多台泵上的参数并不总是相同变得更加困难。所以我的第一个猜测是带有泵 id 和时间戳的键值存储系统。同时我认为这是最好的也是唯一的方法。我无法想象有 100 个神秘列的行是正确的方法。
  • 测试两者。人生本就充满惊喜。它让你看起来对不同的做事方式持开放态度。
猜你喜欢
  • 1970-01-01
  • 2011-06-05
  • 2014-11-13
  • 1970-01-01
  • 1970-01-01
  • 2015-11-10
  • 2010-09-28
  • 1970-01-01
  • 2018-01-31
相关资源
最近更新 更多