不转储主键的情况下,对MySQL表进行转储

46

我有一个表分布在两台运行 MySql 4 的服务器上。 我需要将它们合并到一个服务器中,以供我们的测试环境使用。

这些表每个都有数百万条记录,它们之所以分布在两个服务器上,是因为它们太大了。 对表进行任何更改和分页都会给我们带来巨大的性能损失。

由于它们在生产环境中,因此无法在现有服务器上以任何方式对其进行修改。

问题在于主键是唯一的自动递增字段,因此存在交叉点。

我一直在尝试使用 mysqldump 命令来忽略某些字段,但 --disable-keys 只是改变了表,而没有完全去除键。

此时,看起来我需要修改数据库结构,以利用校验和或哈希作为主键的组合,这两个独特的字段实际上应该是唯一的...我真的不想这样做。

求助!

11个回答

36
为了解决这个问题,我查找了这个问题,找到了 @pumpkinthehead 的答案,并意识到我们只需要在每一行中查找+替换主键为NULL,这样MySQL将使用默认的自动增量值。

(你的完整mysqldump命令) | sed -e "s/([0-9]*,/(NULL,/gi" > my_dump_with_no_primary_keys.sql

原始输出:

INSERT INTO `core_config_data` VALUES
    (2735,'default',0,'productupdates/configuration/sender_email_identity','general'),
    (2736,'default',0,'productupdates/configuration/unsubscribe','1'),

转换后的输出:

INSERT INTO `core_config_data` VALUES
    (NULL,'default',0,'productupdates/configuration/sender_email_identity','general'),
    (NULL,'default',0,'productupdates/configuration/unsubscribe','1'),

注意:这仍然是一个hack;例如,如果您的自增列不是第一列,则会失败,但99%的情况下可以解决我的问题。


1
如果您使用支持正则表达式替换的文本编辑器,可以查找“VALUES \([0-9]+”并替换为“VALUES \(NULL” ,这个正则表达式解决方案也可以扩展到自增不在第一列的表。 - Alejandro Cortes
这可能是一个hack,但它确实是正确的解决方案。 - GideonleGrange

28

如果您不在乎自动增量列的值,那么只需加载第一个文件,重命名表,然后重新创建表并加载第二个文件。最后,使用

INSERT newly_created_table_name (all, columns, except, the, auto_increment, column)
       SELECT all, columns, except, the, auto_increment, column
         FROM renamed_table_name

看起来很有前途,我会开始尝试。 - Zee Spencer
我有一个外键字段引用主键。这个解决方案是否保持了这种引用完整性?看起来好像没有。 - aamiri
1
不会的,它会改变主键。 - longneck
作为一种替代方案,如果您使用phpmyadmin或类似的mysql workbench工具,您可以执行mysql dump并从结果中排除某些列。 - Shawn

14

您可以创建一个没有主键列的表视图,然后在该视图上运行mysqldump。

因此,如果您的"users"表具有列:id、name和email。

> CREATE VIEW myView AS
  SELECT name, email FROM users

编辑:啊,我明白了。我不确定是否还有其他方法。


不支持mysql 4 :(. 我知道,很遗憾 :(. - Zee Spencer
根据表的大小,您可以创建一个临时副本(不包括主键)而不是创建视图。 - balpha
表格的记录数量在数百万范围内。 - Zee Spencer
尝试在phpmyadmin中导出视图将导致没有行。 - fionbio

7
这真是件麻烦事。为了解决这个问题,我会运行类似以下代码的内容:
sed -e "s/([0-9]*,/(/gi" export.sql > expor2.sql 

在转储数据时,需要去除主键然后进行处理。
sed -e "s/VALUES/(col1,col2,...etc.) VALUES/gi" LinxImport2.sql > LinxImport3.sql

除主键外,适用于所有列。当然,您必须小心,确保([0-9]*,不会替换您实际需要的任何内容。

希望这能帮助到某些人。


1
我必须从正则表达式中移除 i 标志,但除此以外,这个工作得很好!谢谢! - joshwhatk
2
当使用 mysqldump --complete-insert ... 时,您不需要第二个语句。 - phil294

7
  1. 克隆您的表格
  2. 在克隆表中删除列
  3. 使用-c选项转储不带结构的克隆表格(但保留完整插入)
  4. 导入到您想要的位置

4
SELECT null as fake_pk, `col_2`, `col_3`, `col_4` INTO OUTFILE 'your_file'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM your_table;

LOAD DATA INFILE 'your_file' INTO TABLE your_table
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n';

为了增加一些花哨的效果,您可以在接收表上设置一个“before insert”触发器,在插入发生之前为每一行设置新的主键,从而使用常规转储并清除您的主键。尚未经过测试,但我对此感到非常自信。

2

使用虚拟临时主键:

正常使用mysqldump,例如,您的主键是“id”。编辑输出文件并向表结构中添加一行“dummy_id”,其类型与“id”相同(但不是主键)。然后修改INSERT语句,并将“id”替换为“dummy_id”。导入后,删除“dummy_id”列。


0

jimyi 正在走上正轨。

这就是自增键让人头疼的原因之一。一个解决方案不是删除数据,而是添加数据。

CREATE VIEW myView AS
SELECT id*10+$x, name, email FROM users

(其中$x是唯一标识原始数据库的单个数字)可以在源数据库上创建视图(您暗示可能不可能),或者使用类似于Autocracy所描述的提取例程,或将数据加载到测试盒的分段表中。

另外,不要在测试系统上创建表 - 而是为src数据放置单独的表,然后创建一个从两个表中获取数据的视图:

CREATE VIEW users AS
(SELECT * FROM users_on_a) UNION (SELECT * FROM users_on_b)

C.


我不明白创建视图如何有帮助,因为mysqldump不会输出视图数据,只会输出CREATE VIEW语句,所以你并没有更进一步。如果你只是使用视图来创建一些临时表,那么这个视图就是多余的。如果你接下来要使用select .. into outfile,那么这个视图再次就是多余的。我错过了什么吗? - Tom Auger

0

我喜欢使用临时表的方法。

create temporary table my_table_copy
select * from my_table;

alter table my_table_copy drop id;

// Use your favorite dumping method for the temporary table

像其他解决方案一样,这并不是一个适用于所有情况的解决方案(特别是考虑到 OP 的数百万行数据),但即使在 100 万行数据下,它也需要几秒钟才能运行,但是可以正常工作。


0
我一直在使用的解决方案是,对要导出的数据进行常规的 SQL 导出,然后使用正则表达式查找和替换编辑器从插入语句中删除主键。个人使用 Sublime Text,但我相信 TextMate、Notepad++ 等也可以做到同样的效果。
然后,我只需将查询复制并粘贴到 HeidiSQL 的查询窗口或 PHPMyAdmin 中应该插入数据的任何数据库中运行查询。如果有大量数据,我会将插入查询保存到 SQL 文件中,并使用文件导入代替。使用大量文本进行复制和粘贴通常会使 Chrome 冻结。
这听起来可能很麻烦,但我很少在导出和导入之间使用超过几分钟的时间。可能比接受的解决方案所需的时间少得多。我已经在数十万行上使用了这种解决方法,没有问题,但我认为当你达到数百万行时,它可能会变得棘手。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接