这是对我的问题“高效存储 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/