大型数据集的数据库设计
Posted
技术标签:
【中文标题】大型数据集的数据库设计【英文标题】:Database Design for large datasets 【发布时间】:2019-08-14 03:48:01 【问题描述】:我目前正在设计一个数据库表,其中我们将有几亿条记录,我想知道管理它的最佳方法是什么。使用这些类型的数据集,我们最终会遇到维护问题,例如表恢复或更改表需要很长时间。现在我对如何处理这个问题有了一些想法,但也许有更好的方法?
由于我们的数据越新越相关,我们可以将其拆分为较短的时间范围(例如过去 30 天)和旧数据集(比过去 30 天更早)。为此,我看到了两种可能性:
将其分成两个分区,当前分区和旧数据分区
优点:
当前数据分区的表还原会很快,因为它不是那么大。在紧急情况下,我们会先恢复它,然后仅使用该数据重新启动系统。这对用户来说是可接受的场景 我们可以正常读取/写入表 - 因此不需要特定的应用程序逻辑缺点:
迁移脚本(更改表,我们可以在线使用,但如果我做对了,这并不适用于每个用例)需要很长时间,因为它们仍然针对两个分区运行。对此的解决方案是将旧数据分区为用户脱机并在后台运行。因此,用户在此期间将无法访问旧数据,但这没关系。这样的事情可能吗?手动将其拆分为两个表并通过夜间作业移动数据。在上面我们放置一个视图来选择数据
优点:
我们可以通过不再将旧数据表包含在视图中并运行更改表脚本来使旧数据表脱机。完成后,将其放回视图中。由于用户不会再找到数据,他也将无法修改它 表恢复会很快,因为我们会首先恢复当前表,更新视图并让用户再次使用它。旧数据表的恢复需要一段时间,但没关系缺点:
既然是视图,我们只能通过它进行选择。如果涉及到修改数据,我们需要为两个表编写更新查询,因为用户想要更新旧数据。因此,从应用程序的角度来看,它需要自定义逻辑所以我的问题是,在这种情况下,最佳做法是什么?你会建议做什么?
谢谢
【问题讨论】:
您还可以使用更多分区按年和月进行子分区。我假设您将使用 InnoDB 引擎? InnoDB 引擎上的大多数 DDL 语句都可以在线运行,这意味着表或分区在更改时不会被锁定 你说的是一年插入 300M 行吗?仅 10 次/秒。直到每秒 100 次我才会兴奋。 【参考方案1】:(关注新旧数据)
如果表按时间顺序排序,并且您主要访问“新”数据,那么大量缓存和它提供的性能是自动内置的。
请务必使用 InnoDB 并将 PRIMARY KEY
设为 AUTO_INCREMENT
(或以 DATETIME
开头)。
让我们计算一些数字。如果表中有 300M 行,每行占用 100 个字节(一个简单的经验法则),那么表的数据占用 30GB。索引和其他表还会有更多。如果您在具有 64GB RAM 的服务器上运行(今天并非不合理),那么一切都可能适合 RAM 并且不需要太多 I/O。
相反,如果您只有 8GB 的 RAM,并且大部分活动都在表的最新 10% 中,那么再次,它将被很好地缓存。
(注意:I/O 是性能中最大的硬件组件。)
通常会影响大型表设计的是索引、查询公式,甚至是整体架构。但是,由于您没有这方面的详细信息,所以我跳过了。
您提到了一种粗略的手动分区表的方法。内置了一些东西:PARTITIONing
。但它不可能有助于插入、更新或选择,所以我不建议在没有进一步讨论的情况下使用它。
如果您最终要清除“旧”数据(比如一年后),那么PARTITIONing
是一个好主意。如果表只保存 1 年的数据,我会使用每周分区。如果您需要,我们可以进一步讨论。 但是请注意,唯一的好处是通过DROP PARTITION
删除旧数据;分区是。
SUBPARTITIONs
帮不上什么忙。
【讨论】:
【参考方案2】:几亿是很多,但不是今天的大型数据集。大型数据集有数十亿条记录。我认为这里的问题是,您的数据增长速度有多快? 以及您针对它运行什么类型的查询?如果您的数据增长非常缓慢,任何数据库软件都可以即使没有分区,也可以足够快地处理该数量。如果它增长得很快,做一些分区可能是个好主意。
如果您有 OLTP 工作负载,即具有高延迟但数量众多的小查询,最好将热数据保存在单独的位置。如果它们取决于时间,我建议您使用基于日期时间列的本地分区,按年份分区。这样,大多数基于最近数据的查询只会检查最新的分区,并且可能会检查整个数据集的一小部分。
如果recent表示很短的时间,比如1个月,那么上面的方法虽然有用,但是还不够。因此,您可以在其上创建另一个 hot-data-table。现在您有一个按年份分区的大数据表(始终包含所有数据)和一个包含最新数据的小表。要克服缺点,您可以这样做:
更新/插入/删除 所有查询都转到主表;如有必要,每个操作的触发器将复制对热数据表的操作。 (数据库级逻辑)或者您可以将相关查询发送到两个表,并确保它们在应用程序级别(应用程序级别逻辑)是一致的。这个可能更高效,因为 mysql 触发器会进一步降低数据库速度。
SELECT 查询将根据查询转到新表,否则转到主表(按年份分区有助于提高性能)。如果您想灵活一些,也可以使用代理来完成查询拆分。 Proxysql 可以轻松处理。它还有其他好处,例如缓存和连接多路复用。
要从热数据表中丢弃旧数据,您可以每天执行一个事件以删除超过 1 个月的记录。如果您有成千上万的要删除,您应该以较小的块删除它们,以防止出现锁定、滞后和大量资源消耗等问题。另一种方法是使用 is_deleted 列来识别过时的记录,并以此进行分区。随时删除分区是即时的。
对于非阻塞 DDL 操作,有一些开源工具可以在线迁移您的架构,而不会降低很多性能。查看pt-schema-change 和ghost。
【讨论】:
您不能将大定义为记录中的数字在您的问题中,您或多或少地指向大数据术语。在我看来,如果您处理存储在服务器 RAM 中的大数据。这意味着 8 Gb RAM 上的 9 Gb 可以被认为是“大数据”,而在 128 Gb 井上是“小数据”。众所周知,数据库服务器速度较慢,然后需要磁盘 I/O 来处理数据库而不从其访问它记忆 @RaymondNijland 你在理论上是对的,但问题的标题是“大型数据集”,并没有提到他拥有的资源。所以我想大致指出,对于今天的软件来说,几亿是没有什么可处理的 是的,提交并不是要以任何方式“攻击”您的答案,我也注意到这条评论 “所有查询都转到主表;每个操作的触发器都会在热数据表,如有必要。(数据库级逻辑)" 更好的方法可能/可能是切换到其他数据库系统(如 PostgreSQL),它本机支持materialized views/tables,它可以保存定义的表表达式在 SQL 2003 中 .. 我仍在等待 MySQL 支持此功能 我没有被冒犯:) 另外,我同意物化,但没有提到因为客户标记为 mysql。但是,最近用于 mysql sharding 的 vitess.io 添加了该功能,看起来很棒。有兴趣的可以去看看。 我建议触发器的成本不仅仅是拥有一个表(PARTITIONed
与否)。以上是关于大型数据集的数据库设计的主要内容,如果未能解决你的问题,请参考以下文章