使用mysqldump来格式化每行一个插入?

这已被问了几次,但我找不到解决我的问题。 基本上,当使用mysqldump(这是MySQL Workbenchpipe理工具的内置工具)使用扩展插入转储数据库时,会得到大量的长数据。 我明白为什么这样做,因为它通过插入数据作为一个命令(特别是在InnoDB上)来加速插入,但格式化使得真正难以在转储文件中查看数据,或者使用diff工具比较两个文件如果您将它们存储在版本控制等。在我的情况下,我将它们存储在版本控制中,因为我们使用转储文件来跟踪我们的集成testing数据库。

现在我知道我可以closures扩展插入,所以我会得到一个插入每行,这工作,但任何时候你用转储文件进行恢复,它会变慢。

我的核心问题是,在转储文件时,我们曾经使用过的旧的工具(MySQL Administrator),它基本上做了同样的事情,但是它规定INSERT语句每行放置一个插入,而仍然进行批量插入。 所以,而不是这个:

INSERT INTO `coupon_gv_customer` (`customer_id`,`amount`) VALUES (887,'0.0000'),191607,'1.0300'); 

你得到这个:

 INSERT INTO `coupon_gv_customer` (`customer_id`,`amount`) VALUES (887,'0.0000'), (191607,'1.0300'); 

无论我尝试什么select,似乎都没有办法像这样得到一个转储,这真是两全其美。 是的,它需要更多的空间,但是在需要人类阅读文件的情况下,这使得它更加有用。

我错过了什么,有没有办法用MySQLDump来做到这一点,或者我们都倒退了,旧的(现在不推荐使用的)MySQLpipe理员工具中的这个function已经不可用了?

使用默认的mysqldump格式,转储的每个logging都将在转储文件(即sql文件)中生成一个单独的INSERT命令,每个都在其自己的行上。 这对于源代码控制(例如,svn,git等)来说是非常完美的,因为它可以使得diff和delta分辨率更加精细,并且最终得到更有效的源代码控制过程。 但是,对于大小较大的表,执行所有这些INSERT查询可能会使得从sql文件恢复的速度过慢。

使用–extended-insert选项通过在转储的sql文件的一行中将所有logging包装成单个INSERT命令来修复多个INSERT问题。 但是,源代码控制过程变得非常低效。 整个表格内容在sql文件的单行中表示,如果单个字符在该表格中的任何位置发生更改,则源代码pipe理会将整行(即整个表格)标记为版本之间的差异。 而且,对于大型表格来说,这却否定了使用正式的源代码pipe理系统的许多好处。

所以理想情况下,为了高效地恢复数据库,在sql文件中,我们希望每个表都由一个INSERT表示。 对于一个高效的源代码控制过程,在sql文件中,我们希望该INSERT命令中的每个logging都驻留在它自己的行上。

我的解决scheme是以下备份脚本:

 #!/bin/bash cd my_git_directory/ ARGS="--host=myhostname --user=myusername --password=mypassword --opt --skip-dump-date" /usr/bin/mysqldump $ARGS --database mydatabase | sed 's$VALUES ($VALUES\n($g' | sed 's$),($),\n($g' > mydatabase.sql git fetch origin master git merge origin/master git add mydatabase.sql git commit -m "Daily backup." git push origin master 

结果是一个sql文件的INSERT命令格式如下所示:

 INSERT INTO `mytable` VALUES (r1c1value, r1c2value, r1c3value), (r2c1value, r2c2value, r2c3value), (r3c1value, r3c2value, r3c3value); 

一些说明:

  • 命令行上的密码…我知道,不安全,不同的讨论。
  • –opt:其中,打开–extended-insert选项(即每个表一个INSERT)。
  • –skip-dump-date:mysqldump通常在创build时在sql文件中放入一个date/时间戳记。 当版本之间的唯一增量是date/时间戳时,这可能会在源代码pipe理中变得烦人。 操作系统和源代码pipe理系统将对文件和版本进行date/时间戳记。 它不是真的需要在SQL文件中。
  • git命令不是基本问题(格式化sql文件)的核心,但是显示了如何将我的sql文件恢复到源代码pipe理,类似的东西可以用svn来完成。 当把这个sql文件格式与你select的源代码控制结合起来的时候,你会发现当你的用户更新他们的工作拷贝时,他们只需要在互联网上移动变化logging(deltas),他们就可以利用diff工具轻松查看数据库中的logging已更改。
  • 如果您正在转储驻留在远程服务器上的数据库(如有可能),请在该服务器上运行此脚本,以避免每次转储都在整个networking中推送整个数据库的内容。
  • 如果可能的话,在运行此脚本的同一台服务器上为您的sql文件build立一个工作源代码控制库; 从那里检查他们到存储库。 这也有助于防止在每次转储时都要将整个数据库推送到整个networking。

尝试使用以下选项:– skip-extended-insert

它为我工作。

正如其他人所说的使用sedreplace“),(”是不安全的,因为这可能会出现在数据库中的内容。有一种方法可以做到这一点:如果您的数据库名称是my_database然后运行以下:

 $ mysqldump -u my_db_user -p -h 127.0.0.1 --skip-extended-insert my_database > my_database.sql $ sed ':a;N;$!ba;s/)\;\nINSERT INTO `[A-Za-z0-9$_]*` VALUES /),\n/g' my_database.sql > my_database2.sql 

你也可以使用“sed -i”来replace内联。

这是这个代码在做什么:

  1. –skip-extended-insert会为你所有的行创build一个INSERT INTO。
  2. 现在我们使用sed来清理数据。 请注意,sed的常规search/replace适用于单行,所以我们无法检测到“\ n”字符,因为sed一次只能运行一行。 这就是为什么我们把“:a; N; $!ba” 基本上告诉sedsearch多行并缓冲下一行。

希望这可以帮助

关于将转储存储到csv文件?

与mysqldump使用–tab选项是这样的:

 mysqldump --tab=/path/to/serverlocaldir --single-transaction <database> table_a 

tab选项产生2个文件,一个文件-table_a.sql-只包含表格create语句和其他文件-table_a.txt-包含制表符分隔的数据。

RESTORING

你可以通过LOAD DATA恢复你的表格

 LOAD DATA INFILE '/path/to/serverlocaldir/table_a.txt' INTO TABLE table_a FIELDS TERMINATED BY '\t' ... 

LOAD DATA通常比使用INSERT语句快20倍

如果您必须将数据恢复到另一个表(例如用于检查或testing目的),则可以创build一个“镜像”表:

 CREATE TABLE table_for_test LIKE table_a; 

然后将csv加载到nwe表中。

 LOAD DATA INFILE '/path/to/serverlocaldir/table_a.txt' INTO TABLE table_for_test FIELDS TERMINATED BY '\t' ... 

比较

一个csv文件最简单的比较或内部查看…也可以使用常见的工具,如ExcelAccess或命令行( diffcomm等)的非SQL技术用户…)

恐怕这是不可能的。 在旧的MySQLpipe理员中,我编写了用于转储db对象的代码,这是完全独立于mysqldump工具的,因此提供了许多其他选项(如格式化或进度反馈)。 在MySQL Workbench中,决定使用mysqldump工具,除了在某些方面向后退一步,并产生版本问题外,还有一个优势,就是始终保持服务器的最新状态。

所以简短的答案是:格式化目前不可能与mysqldump。

我发现这个工具对处理扩展插入非常有用: http : //blog.lavoie.sl/2014/06/split-mysqldump-extended-inserts.html

它parsingmysqldump输出并在每条logging后插入换行符,但仍使用更快的扩展插入。 与sed脚本不同的是,如果正则expression式碰巧在string内部匹配,那么在错误的地方就不应该有任何破坏行的风险。

我喜欢Ace.Di的解决scheme,直到我得到这个错误:sed:无法重新分配内存

所以我不得不写一个小的PHP脚本

 mysqldump -u my_db_user -p -h 127.0.0.1 --skip-extended-insert my_database | php mysqlconcatinserts.php > db.sql 

PHP脚本还为每个10.000行生成一个新的INSERT,以避免内存问题。

mysqlconcatinserts.php:

 #!/usr/bin/php <?php /* assuming a mysqldump using --skip-extended-insert */ $last = ''; $count = 0; $maxinserts = 10000; while($l = fgets(STDIN)){ if ( preg_match('/^(INSERT INTO .* VALUES) (.*);/',$l,$s) ) { if ( $last != $s[1] || $count > $maxinserts ) { if ( $count > $maxinserts ) // Limit the inserts echo ";\n"; echo "$s[1] "; $comma = ''; $last = $s[1]; $count = 0; } echo "$comma$s[2]"; $comma = ",\n"; } elseif ( $last != '' ) { $last = ''; echo ";\n"; } $count++; }