9

我有一个巨大的 InnoDB 表(>1TB,>1B 行),我想分片:我想从那个大表中创建多个较小的独立表。

怎么做 ?

我已经尝试过的:

  • 通过从原始表中选择行并将它们插入分区来将行移动到分区。这需要很长时间,并且在操作期间保持行同步是很困难的(但似乎可以使用触发器,只要分区在同一台服务器上)。我还没有找到一个现成的工具来做到这一点。
  • 复制整个表,然后删除不属于分区的行。仍然很慢,尤其是考虑到桌子的大小。显然,这就是 MySQL Fabric 所做的。

随机的疯狂想法:

  • 离线拆分.idb文件,并将其导入服务器,但我不知道是否存在能够执行此操作的工具。

显示创建表:

CREATE TABLE `Huge` (
  `account_id` int(11) NOT NULL,
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `foo` varchar(255) NOT NULL,
  `bar` int(11) NOT NULL,
  `baz` char(2) NOT NULL,
  PRIMARY KEY (`account_id`,`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;

分片键是 account_id。当前的主键是(account_id,id)使行由account_id.

是否有任何工具可以自动执行此任务?有没有更好的方法来做到这一点?

4

2 回答 2

10

“分片”是在多台服务器之间拆分数据(通常是一张表)。“分区”是将表拆分为同一服务器上的多个子表。你在做什么?Fabric 进行分片。您对 .ibd 的评论暗示您正在考虑分区。

假设你想要PARTITION一张大桌子,我需要先问为什么。这是一个严肃的问题,因为大多数(我的意思是大多数)人认为分区会神奇地产生一些好处,而实际上它不会。我相信只有 4 个分区用例。您的情况是否属于其中任何一种?

另一方面,如果您想要分片,请提供SHOW CREATE TABLE并讨论您将分片的列。

编辑(明确目标后)

我希望你没有明确的FOREIGN KEYs;它们不适用于分区或分片。

`id` bigint(20) NOT NULL AUTO_INCREMENT,
UNIQUE KEY `id` (`id`)

是两个方面的问题。

  • 没有必要做id UNIQUE; 对 an 的唯一要求AUTO_INCREMENT是它是某个索引中的第一列。所以这对系统的负担会更小:

    索引(id)

  • AnAUTO_INCREMENT确实适用于PARTITIONed表,但不适用于分片表。您将需要评估id. 要么它只在一个分片内唯一是可以的,那么就没有真正的问题。如果id需要在所有分片中保持唯一性,那就更难了。可能唯一的解决方案是拥有一种从某个中央服务器获取 id 的技术。但是,这会导致单点故障和瓶颈。如果您需要朝那个方向发展,我可以就如何避免这些缺点提出建议。

如何迁移到最终的分片系统?

我不建议任何题外话PARTITIONing,从长远来看它不会真正有帮助。并且成本REORGANIZE PARTITION很高——复制所有行,包括提取的行和剩余的行。 编辑:如果您确实使用分区,请使用pt-online-schema-change以最少的停机时间进行拆分。

相反,我建议完善一种工具,将一个account_id分片从一个分片迁移到另一个分片。这必须是自定义代码,因为可能还有其他表(以及表之间的引用)会因将帐户移动到不同的服务器而受到影响。从长远来看,这将有助于负载平衡、硬件升级、软件升级,甚至架构更改。当您需要更改某些内容时,请使用新的 OS/version/schema/whatever 创建一个新的分片并将用户迁移到它。

这个工具的简单方法是

  1. “阻止”为该帐户写入
  2. 将记录复制到新分片
  3. 更改网守以知道该帐户现在在新分片上
  4. 取消阻止写入
  5. 最终(并逐渐DELETE在旧分片上排行

如果帐户“小”,这不是什么大问题。但是,如果您需要最少的停机时间(写入被阻止),那么我们可以讨论一种更复杂的方法。

(如果你没有猜到,我已经“去过那里,做到了”。)

于 2015-06-27T05:49:49.920 回答
0

您可以修改表结构。该表不是2NF因为 id它是唯一的(候选键)而出现在primary key(表的任何其他属性都喜欢fooaccount_id依赖于主键的子集 -ie id)。以下可以在较少约束的情况下完成相同的工作:

 id bigint(20) not null auto_increment primary key

现在,通过在上面创建索引,account_id您可以获得当前主键(account_id,id)的所有好处。

作为第二个建议,您可以将表格分成两部分:一部分包含foo,另一部分用于其余列。这样,您将拥有一个相对较小的表(第二个表),它具有固定的行长度(因此速度更快)来存储大部分数据(列),以及一个比当前表更小的可变行长度表,并且将被称为 less频繁地。

综上所述,在对表进行分区之前,我建议您将其拆分为:

CREATE TABLE `fixed_length` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT primary key,
  `account_id` int(11) NOT NULL,
  `bar` int(11) NOT NULL,
  `baz` char(2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;

create table `variable_length`(
  `id` bigint(20) NOT NULL primary key,
  `foo` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;

和一个indexfor account_id

 create index ix_account_ix on fixed_length(account_id);

现在,如果您想通过 对数据进行分区account_id,您可以保持fixed_length原样并仅在variable_lenth表上进行分区(通过您选择的任何方法)。

于 2015-07-04T20:19:04.923 回答