在MySQL中拆分表。好的做法?


14

我已经开始研究一个现有项目,并且以前的开发人员已将一个表拆分为10个具有相同模式但数据不同的单独表。

这些表如下所示:

[tableName_0]
[tableName_1]
[tableName_2]
[tableName_3]
[tableName_4]
[tableName_5]
[tableName_6]
[tableName_7]
[tableName_8]
[tableName_9]

主键是一个整数id字段。该应用程序使用哈希算法(idmod 10)来知道在查找时要访问哪个表。例如id= 10将导致[tableName_0]

这些表加起来可能有100,000行,并且增长率相对较低。

因此,我的问题是,这是否是可行的解决方案,或者即使在任何情况下都是好的做法。我的理论是推动将它们组合在一起,因为这样会使事情变得更容易,直到UNIONs等。主要缺点是更改所有应用程序代码以及从长远来看是否值得。

Answers:


17

我认为每个人都使这一问题变得过于复杂。这里的关键点是:

这些表加起来可能有100,000行,并且增长率相对较低。

对于任何RDBMS来说,这都是小菜一碟选择一个表,对其进行正确索引,然后将其视为已解决的问题。

在开始处理大量数据(想想数十亿行及以上)之前,无需考虑分区(无论是“自制”分区还是其他方式)。


3

您可以使用合并表,但是它们与4.x版本相比过时了。鉴于您的应用程序是按以下方式进行手动分区的:a)您正在运行的是旧版本,或者b)原始开发人员不知道表分区。

简而言之,如果您运行的是5.1+,则可以让mysql为您进行分区。参见 http://dev.mysql.com/doc/refman/5.1/en/partitioning.html。 如果您使用的是5.5,则应检查这些特定文档,因为会发现一些差异。

分区有很多优点。但是,它实际上取决于手头的数据集,访问模式以及如何对其建立索引。另外,请记住我的以下评论是在mysql 5+分区的上下文中,而不是较旧的mysql合并表;尽管有时会根据分区进行讨论。

一些例子:

  • 基于频繁访问的查找键的直接存储(或散列)。如果您几乎总是要通过主键或其他唯一键来查找,那么mysql可以将搜索空间减少多少倍于您拥有多少个分区。但是请注意,如果您按一个键进行分区,然后频繁地按另一个键进行搜索,则可能是有害的。如果按键搜索,则数据未按分区进行分区,那么它必须对查询进行更多搜索(坦率地说,每个分区一个,b / c,它不知道数据在哪里)
  • 考虑一下情况,如果您有一组按日期增长的临时记录,并且定期删除上个月的记录。如果您要按日期进行分区,则可以删除一个分区,该分区与删除表一样快,无论其大小如何。如果要按日期对此类表进行修剪,则必须发出一个或多个DELETE查询,在该查询中删除每行。不利的一面是,一旦达到该情况下的最大日期,mysql便不会自动创建新分区。您需要自己构建的额外维护脚本来根据需要添加分区。
  • 如果您使用的是myisam,则检查和恢复速度会更快。考虑一个100G的myisam表。如果要恢复崩溃的表,则至少需要大约100G的备用磁盘空间。如果将其划分为10个大小相等的不同块,那么您仅需要10G的空间(以及较少的key_sort_buffer内存即可快速恢复);但需要为每个分区进行一次迭代。

因此,总而言之,分区表的一般方法可以提供很多好处。但是它不是一个妙法可以不考虑盲目地应用于访问模式和如何正是你所分割。

我可以想象这样一种情况:所需的分区是非常特定于应用程序的,并且更适合将逻辑放在应用程序层中。但是,鉴于您对直线模量10的描述,这种情况似乎并非如此。

编辑

在写我的描述时,我忘记了您说您的表是10万行。没有表的完整架构以及平均行长度,这很难确定,但是总的来说,即使是适度的硬件,听起来也中等大小。同时,如果它没有像现在这样或在可预见的将来引起问题,那就不要花时间并通过改变来引入风险。


3

以前的开发人员为您完成的工作是构建自己的哈希分区实现。MySQL从MySQL 5.1本身就真正支持此功能:

http://dev.mysql.com/doc/refman/5.1/zh-CN/partitioning-hash.html

我想不出一个很好的理由,所以要实现自己的哈希散列而不是依靠本机版本[1]。执行模式更改将是一场噩梦。

我也很少建议按哈希分区(本机实现)。我认为如果可以使用它一次并行搜索每个分区(MySQL不会这样做)将很有用。如果您需要跨多个分区进行搜索,那么您描述的方案通常会慢很多。

[1]但是,对于某些其他分区类型,滚动自己的分区可能很有意义。MySQL强迫您将分区键作为主键和所有唯一索引的一部分。


2

针对这个问题:

这是否是可行的解决方案

恕我直言,这似乎是不必要的开销。您可以简单地对单个表进行正确的索引和分区,除非描述中未透露其他信息。

针对这个问题:

...如果在任何情况下都是好的做法

恕我直言,根据上下文的不同,垂直分片可能很有意义。当我看到此消息时,通常采用某种日志形式。假设我们将其用于Web服务器日志,并且希望按月进行分区。与其每天更改现有表,不如每天创建一个新表并将行记录到该表中。

例如,假装网络日志表可能采用以下形式:

datetime TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
uri VARCHAR(1024),
host VARCHAR(255),
user_agent VARCHAR(255),
etc...

您的解决方案根据需要在Weblog数据库中创建表:

weblogs.20120301
weblogs.20120302
weblogs.20120303

等等

这样,数据保持可维护和可搜索的。提取成为正常的周期性过程。对较旧数据的操作不会锁定连续操作。

在您介绍的场景中,无论如何您都被锁定在一个结构中,那么为什么不使用为此目的而优化的单个表呢?基于算法的行存储似乎是粗略且容易出错的。


0

如果查询针对大量数据,则按查询条件对数据进行拆分将显着提高性能。但是,如您所见,这种拆分带来了一些编程问题。

所以问题是:这种拆分是否值得提高性能,还是会损害性能?

如果您有一个需要锁定多个表上的多行的事务,并且存在问题(例如,死锁或事务超时),则您可能希望将它们合并到单个表中并重写SQL以修复问题。

在考虑是否拆分表时,我曾经考虑过在性能提升和编程复杂性之间进行权衡。

在您的情况下,修改现有代码可能是使代码易于维护的长期解决方案。我建议尝试元编程。例如,使用StringTemplate动态生成SQL。如果对现有代码的修改太难了,我喜欢从元编程引擎生成SQL。


0

当您需要将文件存储在表中时,使用此方法有助于导出,修复和还原。

我有大于30 Gb的表划分为10个表。这些表只有ID-BLOB,对我来说很容易保留。而且我使用MyISAM来保存INNODB缓冲区。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.