根据列的值快速拆分 MySQL 表

Posted

技术标签:

【中文标题】根据列的值快速拆分 MySQL 表【英文标题】:Fast splitting a MySQL table based on the values of a column 【发布时间】:2022-01-05 23:47:55 【问题描述】:

我在自己的计算机 (Win10) 上有一个相当大的 mysql 表 (~600G),结构如下。

  id var1  var2 var3
   a  val1  1    5
   b  val1  2    6
   c  var2  3    7
   d  var2  4    8

idvar1 都已编入索引。我想根据 var1 的值将该表拆分为几个子表。也就是说,

table_var1

id var1  var2 var3
a  val1  1    5
b  val1  2    6

对于表'table_var2':

id var1  var2 var3
c  val2  3    7
d  val2  4    8

我使用了以下代码

CREATE TABLE table_var1 LIKE original_table;
INSERT INTO  table_var1 SELECT * FROM original_table where var1=val1;


CREATE TABLE table_var2 LIKE original_table;
INSERT INTO  table_var2 SELECT * FROM original_table where var1=val2;

我的问题与this 非常相似。我想加快拆分表的速度,但是由于数据库在我自己的计算机上,如果我没记错的话,partition 并没有真正的帮助(当有多个物理硬盘可用时,这更有帮助?)。

有没有提高分表性能的建议?

【问题讨论】:

为什么要拆分表?我想不出这样做的充分理由 您遇到的实际问题是什么? @ysth 我需要加快拆分速度。我需要对某些列进行进一步处理(例如,基于 var2 或 var3 为表创建更多列),但是,对于不同的 var1 值,操作会有所不同,因此,我想将此表拆分为子表和对子表分别执行这些操作。 不,您希望通过拆分解决什么问题?一般来说,子表是一个糟糕的主意,会让很多事情变得更麻烦 什么版本的 MySQL? 【参考方案1】:

是的,您的两个步骤可能是最快的方法。更快的是并行方法。 (稍后会详细介绍。)

最好在CREATE TABLE 中定义PRIMARY KEY,但延迟添加辅助键,直到填充新表之后。

确保每个步骤都有足够的磁盘空间。 -- 可能 700GB 用于拆分,然后少量用于添加二级索引。

innodb_buffer_pool_size 设置为大约 70% 的 RAM。

如果original_table 和新表都有PRIMARY KEY(id)(或至少以id 开头),则Insert..Select 应该是表扫描并且对于I/O、CPU 和buffer_pool 非常有效。

会有多少新表?

假设不超过 20% 的表有 var1 的特定值,var1 上的索引将被忽略;别担心。 “表扫描”将比使用索引更有效。

可能可以通过运行所有INSERT..SELECTs同时(来自不同的连接)来进一步加快进程。假设 buffer_pool 小于 600GB 的表大小,顺序扫描将涉及该表的多次完全加载——大量 I/O。并行扫描将(可能)导致只获取一次original_table

(使用命令行工具“mysql”,以便您可以并行运行。Workbench 似乎对此不实用。)

也就是说,“计算磁盘命中次数”会在您的特定任务中发挥作用。顺序方法将需要大约 (N+1)x600GB 的数据被铲除。并行方法只涉及大约 2x600GB 的 I/O。即 600GB 读取 + N x 600GB / N 写入每个新表。

如果您有二级索引,这会使顺序与并行的权衡变得复杂。在我给大脑施加压力以做出预测之前,请提供有关索引的建议。

【讨论】:

以上是关于根据列的值快速拆分 MySQL 表的主要内容,如果未能解决你的问题,请参考以下文章

根据一列的值拆分 csv 文件

根据每行列的内容将一个大表拆分为多个表

SQLite 在另一列的值上拆分列

如何根据多列的值拆分数据框

MYSQL表根据列拆分的问题

MySQL 数据库表的垂直拆分