mysql - 高效的 MySQL 模式,对巨大的数据集进行分区(7.300.000.000 行和大约 80 GB 的数据)

标签 mysql optimization partitioning large-data-volumes

这是对我的问题“高效存储 7.300.000.000 行”( Efficiently storing 7.300.000.000 rows) 的跟进。

我决定使用 MySQL 进行分区,初步架构如下所示:

CREATE TABLE entity_values (
  entity_id MEDIUMINT UNSIGNED DEFAULT 0 NOT NULL, # 3 bytes = [0 .. 16.777.215]
  date_id SMALLINT UNSIGNED DEFAULT 0 NOT NULL, # 2 bytes = [0 .. 65.535]
  value_1 MEDIUMINT UNSIGNED DEFAULT 0 NOT NULL, # 3 bytes = [0 .. 16.777.215]
  value_2 MEDIUMINT UNSIGNED DEFAULT 0 NOT NULL, # 3 bytes = [0 .. 16.777.215]
  UNIQUE KEY (entity_id, date_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 PARTITION BY HASH(entity_id) PARTITIONS 25;

这给出:

  • 行数 = 7.300.000.000 行(根据上一篇文章中所述的要求)
  • 大小/行 = 11 字节 (3+2+3+3)
  • 总大小 = 7.300.000.000 行 * 11 字节 = 80.300.000.000 字节 = 80.3 GB
  • Partitions = 25(3.2 GB/分区,分区大小有些随意)

请注意,我已经从原始设计中删除了主键,因为不会使用“id”列。

现在回答我的问题 - 考虑到我之前的帖子和上面的架构中概述的要求,您对可以进行的进一步优化/调整有什么建议吗?还是鉴于我决定使用 MySQL,上述模式是否“最佳”?

更新:我尝试将当前数据集加载到上面的模式中,8.570.532 行占用了 212.000.000 字节的磁盘空间,每行大约有 24.7 字节。

更新:请注意,涵盖 entity_id+date_id 的索引也将用于仅针对 entity_id 的查询。

最佳答案

我不太明白的一件事是您打算如何修剪数据。您每天有 200 万行,但您没有指定计划保留多少数据。在某些时候,您会希望按年龄使数据过期(很有可能)。

在这一点上,您将希望通过删除分区来实现,而不是通过执行删除来锁定每个分区非常长的时间(因为它必须进行全表扫描才能找到要删除的行), 然后让你的 table 不小,因为分区充满了漏洞。

按 entity_id 的散列进行分区对于搜索来说似乎是明智的,但是按时间进行分区可以在修剪旧数据时缓解争用,这绝对是一件好事。

MyISAM 有一个称为“并发插入”的功能,您几乎肯定需要一直使用它以实现并发性和性能;这强制执行“不删除”规则,这意味着您只能通过删除分区来进行删除。

但是删除分区也很好,因为您可以取回磁盘空间。

说了这么多,80G 并没有那么大,我可能想把它全部存储在一个表中,并使用 InnoDB 来实现并发访问。

哦,是的,如果你确实使用了 InnoDB,你可以有一个 entity_id 的主键,date_id,这意味着它会聚类具有相同 entity_id 的行。您可能需要 date_id 上的二级索引以启用高效修剪。

请使用您的生产数据大小对此进行测试,并让我们知道您的发现!

关于mysql - 高效的 MySQL 模式,对巨大的数据集进行分区(7.300.000.000 行和大约 80 GB 的数据),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/666374/

相关文章:

sql-server - SQL Server 2005 按外部引用数据分区表

mysql - 添加拒绝原因的 SQL 脚本

php - Where in 子句使用 order by 获取结果

c++ - MSVC 如何优化静态变量的使用?

php - 需要帮助优化 PHP 函数

mysql - MongoDB - 正确使用集合?

mysql - 对两个表进行分区的最佳策略是什么?

mysql - 如何通过一个查询更新多行?

php - 代码点火器, mysql

mysql - 有索引的查询比没有索引慢