【问题标题】:Optimising Storage Space: Many rows & columns with the same values优化存储空间:许多行和列具有相同的值
【发布时间】:2019-07-31 15:25:24
【问题描述】:

我有多个表,每个表存储超过 1 亿行数据。任何给定列只有几个可能的唯一值,因此许多列都有重复值。

当我最初设计架构时,我决定使用二级链接表来存储实际值,以优化数据库所需的存储空间。

例如:

而不是像这样存储用户代理的表:

  • id (int)
  • user_agent (varchar)

我正在使用 2 个这样的表:

表 1

  • id (int)
  • user_agent_id (int)

表 2

  • id (int)
  • user_agent (varchar)

当有超过 1 亿行时,我发现此架构可以节省大量存储空间,因为只有几百个可能的用户代理,而这些字符串构成了大部分数据。

我遇到的问题是: 使用链接表在许多不同的表中存储如此多的字符串数据会增加开发方面的开销,并且由于需要连接,因此查询数据的速度要慢得多。

我的问题是: 有没有办法可以将所有列放在一个表中,并强制 mysql 不复制具有重复值的列所需的存储?我开始认为必须有一些内置的方法来处理这种情况,但我在研究中没有发现任何东西。

如果我有一列有 10 个唯一值和 1 亿多行,为什么 MySQL 会将每个值(包括重复项)完全保存在存储中,而不仅仅是对唯一值的引用?

谢谢!

【问题讨论】:

  • 您是否尝试过 COMPRESSION 表选项? MYSQL可以为每一页压缩表空间中的数据。
  • @PeterHe - 是的,我所有的表都已经压缩了。在测试时我发现即使每一行都是相同的列的重复值,当切换到 COMPRESSION 时,大小也只会减少 25% 左右。如果我使用关联列和辅助表,则大小会减少 98-99%。使用 ARCHIVE 可以解决我的问题,但鉴于限制,我的应用程序无法解决。
  • 如果您有“10 个唯一值”,请使用 1 字节的 TINYINT UNSIGNED 而不是 4 字节的 INT。这每行节省了 3 个字节,如果在索引中使用则更多。

标签: mysql indexing storage innodb


【解决方案1】:

如果我有一列有 10 个唯一值和 1 亿多行,为什么 MySQL 会将每个值(包括重复项)完全保存在存储中,而不仅仅是对唯一值的引用?

MySQL 无法预测您将始终只有 10 个唯一值。您告诉它存储一个 VARCHAR,因此它必须假定您要存储 any 字符串。如果要使用一个数字来枚举所有可能的字符串,那么这个数字实际上需要比字符串本身更长。

要解决您的问题,您可以使用引用查找表的数字 ID 来优化存储。由于查找表中不同字符串的数量有数百个,因此您至少需要使用一个 SMALLINT(16 位整数)。您不需要使用与 INT(32 位整数)一样大的数字。

在查找表中,将该 id 声明为主键。这样可以尽可能快地进行连接。

如果您想直接进行反向连接 - 查询您的 100M 行表以查找特定用户代理,然后在您的大表中索引 smallint 列。这将占用更多存储空间来创建索引,因此请确保在创建索引之前在每个表中都需要该类型的查询。

另一个建议:获取更大的存储容量。

【讨论】:

  • 仍然不够大,因为 OP 说有“几百”个值要枚举。
  • 谢谢比尔,我发现使用 varchar 外键比使用数字参考 id 更有效且查询速度更快。我的帖子中有详细信息。
【解决方案2】:

经过一些挖掘和测试,我发现似乎是最好的解决方案:使用 varchar 列本身创建索引和外键约束,而不是使用 ID 字段。

INNODB 支持带有 varchar 和 int 的外键:https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html

这是一个例子:

user_agents 表:

  • user_agent(varchar 和唯一索引)

user_requests 表:

  • 身份证
  • user_agent(varchar,引用user_agents表user_agent列的外键约束)
  • other_columns 等...


我发现当使用 varchar 本身作为外键时,mysql 会自行优化存储,并且只会为磁盘上的每个唯一 user_agent 存储 1 个 varchar。添加 1000 万+ user_requests 行向磁盘添加的信息非常少。

我还注意到它比使用 ID 链接表(如在原始帖子中)更有效。 MySQL 似乎在幕后做了一些魔术,可以用磁盘上很少的信息链接列。它的存储效率至少比存储所有字符串本身高 100 倍,比使用 ID 链接效率高几倍。您还可以获得外键和级联的所有好处。查询任一方向的列都不需要连接,因此查询也非常快!

干杯!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 2018-08-18
    • 2014-08-18
    • 2013-05-25
    相关资源
    最近更新 更多