【问题标题】:How to deal with enormous line lengths created by mysqldump如何处理 mysqldump 创建的巨大行长
【发布时间】:2010-11-20 13:56:46
【问题描述】:

我在 cron 作业中使用 mysqldump 来备份超过 200 万行的数据库。

它创建一个文本文件,可用于从命令行恢复数据记录。

我认为在还原之前编辑转储作为更改值和表或列名称的一种快速方式会很有用 - 至少在我了解更多并有信心使用 ALTER 进行此操作之前和更新。

编辑大文本文件并不困扰我,但我惊讶地发现在我的数据库的 250 兆字节转储中,只有大约 300 行。每行大约有 80 万个字符长。

是否有另一种生成转储的方法可以更好地控制行长?

或者我应该使用 sed 或 Perl 等工具对转储进行后处理?

【问题讨论】:

  • 考虑 ;在查询之间作为您的行尾序。
  • 实际上,我使用 Perl 并说 $line =~ s{\).\(}{),\n(}g; 所以我得到了很多额外的行。
  • 也就是说 ;在每个 INSERT into table_name VALUES (..),(..),(..) .. (..) 的末尾已经是我的 eol;整个文件282行,252行以;结尾我选择在逗号后插入换行符
  • 您确定您的实际数据中没有括号-逗号-括号序列吗?
  • 这是mysqldump 中的一个已知缺点。是first reported in 2004。在 2011 年,Tim RikerLon Binder 都建议使用 1 行补丁来修复它。令人难以置信的是,mysqldump 开发人员/维护人员尚未实现此仍然。由于最初的错误报告已关闭(错误且无济于事),因此现在正在跟踪该问题here

标签: mysql mysqldump


【解决方案1】:

默认情况下,mysqldump每个表只生成一个INSERT 命令,从而为每个被转储的表生成一行(非常长的)插入数据。这本质上是因为“批量”插入比为每个表中的每条记录生成单独的INSERT 查询要快得多。

所以,mysqldump 并没有创建任意长的线,您可以强加一些其他截止长度。排长队是有原因的。

如果将INSERTs 分解为多行非常重要,您可以通过以下方式表示:

mysqldump --extended-insert=FALSE --complete-insert=TRUE ...

但是请注意,以这种格式恢复表会花费更长的时间。

【讨论】:

  • 我想知道是否有人可以确认 net_buffer_length 选项也可以正常工作。对我来说,这似乎是一个更好的解决方案。
  • @VoteyDisciple - 这解释了为什么它是一大行 INSERT,但不能解释为什么它是一大行。每个插入行之后很容易有一个换行符,对吧?
  • 哦,确实有这个需求!我们使用 mysqldump 为每个“标签”存储数据库。我们在标签之间进行了一些较小的更新,用一条大线你看不到哪些内容发生了变化,你需要横向滚动到它。
  • 在我看来这只是一个“格式问题”。为什么不生成 ONE INSERT 语句,而是在单独的行中为每一行生成值块。这将使生成的文件易于阅读,并且根本不会影响性能。
  • PHPMyAdmin 生成它的转储文件,每次插入之间都有一个新行。我想这是有需求的。
【解决方案2】:

我正在浏览 MySQL 源代码以寻找解决此问题的方法。最大行长度由变量 opt_net_buffer_length 强制执行,该变量应该与 MySQL 服务器的缓冲区大小匹配。它大得可笑。

但无论如何,这是一个选项,所以就这样做吧:

mysqldump --net_buffer_length=5000 ...

最小值为 4096。

【讨论】:

  • 这会导致包含超过 4K 数据的单个行出现问题吗?
  • @Cyber​​Shadow 好问题。我打赌它会,但我不知道。下次我这样做时,我将尝试将 mysqldump net_buffer_length 与 max_allowed_pa​​cket 匹配,看看是否有效。我刚刚做了一个导入,其中查询大小超过了 16M max_allowed_pa​​cket。甚至 64M 也太小了 - 到 256M 并通过了。所以我下次可能会尝试大约 10M 的 net_buffer_length,我自己,看看会发生什么。
  • @Cyber​​Shadow 不,它不会导致更大的行出现问题 - 它们会占用所需的空间。使用 MariaDB 10.0.21 测试。
  • 性能方面,导入我的 20MB / 335k 行数据库转储:[ 使用单事务转储:22s ] // [ 使用 4096 缓冲区长度转储:1m 44s ] // [ 使用扩展插入=假:????我厌倦了等待并在 33 分钟后 CTRL-Ced ]。所以这个答案无疑是速度和可区分性之间的最佳折衷。注意事项:我随后的转储是相同的,但我没有使用超过 4096 个字符的行数据进行测试。
  • *实际上,考虑一下,如果表中早期的一行被修改或删除,那么所有后续行的内容都会跨块边界偏移,使得后续转储在之后的每一行上都不同那一点。所以也许这毕竟没有很大的可区分性......
【解决方案3】:

我在 MySQL 论坛上看到了一个答案,它最终表明在每个 INSERT 组之后添加 '\n' 是不可能单独使用 mysqldump 的,而不修改源:

扩展格式不能100%正确解析基于逗号 或括号,您将计算字段。最佳解决方案,修复 mysqldump 在输出时换行。

非常小的变化:在第 3506 行,您可以看到行尾在哪里 逗号是输出:
fputc(',',md_result_file); /* Always row break */

只需在第 3506 行之后立即插入此行:
fputc('\n',md_result_file); /* Lon Binder says wrap that line! */

重新编译并完成。

@见http://forums.mysql.com/read.php?28,420002,426110#msg-426110

谢谢朗 B!

(我已经包含了 MySQL 论坛的内容,以防论坛消失。)

【讨论】:

  • 呃,为什么这不是 mysqldump 的选项?这是两全其美的。
  • 请给出mysqldump源的链接。
  • @Speakus - MySQL 归 Oracle 所有,不提供下载或查看单个源文件的直接链接 - 您可以从此处下载源包:dev.mysql.com/downloads/utilities - 只需选择“源”作为平台.
  • 谢谢。对您的评论进行小幅改进:我不应该从您的链接中选择来源,而是从这里选择来源:dev.mysql.com/downloads/mysql + 打开文件 mysql-5.6.20/client/mysqldump.c + 通过评论搜索所需行(我找到了第 3791 行)+按照描述添加新行。另一种获取源代码的方法:mariadb.com/kb/en/mariadb/documentation/getting-started/… + 更改 maria/client/mysqldump.c(第 3928 行)。不幸的是,这两种工具(oracle mysql 和 mariadb)仍然没有解决问题的选项
【解决方案4】:

这个标志也有效:

mysqldump --skip-extended-insert 

--extended-insert=FALSE一样。

【讨论】:

  • 是的,出于某种原因,我更喜欢那个 :) 只是需要这个作为差异,正常的长行让差异真的很痛苦。
  • 每条记录都以INSERT INTO table_name VALUES (...); 开头,这会占用更多空间,但如果从数据中看不出它要进入哪个表,则可以提供一些有用的上下文。
【解决方案5】:

使用正则表达式分割行是不够的,您需要一个能够正确理解引号和转义字符的解析器。

我只是写了一个解析器,因为我找不到:http://blog.lavoie.sl/2014/06/split-mysqldump-extended-inserts.html

【讨论】:

  • 对现有转储非常有用 :)
【解决方案6】:

如果你已经有一个很长的 SQL 转储并且想要轻松阅读它,你可以使用

cat dump.sql  | sed 's$VALUES ($VALUES\n($g' | sed 's$),($),\n($g' | less

cat dump.sql  | sed 's$VALUES ($VALUES\n($g' | sed 's$),($),\n($g' | grep something

【讨论】:

    【解决方案7】:

    使用python 对转储文件进行后处理。你可能比 perl 或 sed 更快乐。

    如果您在 Linux 上运行,则您已经安装了它。如果您在 Windows 上运行,安装程序很轻松。

    不过,在此之前,请学习使用 SQL UPDATE 和 SQL ALTER。以正确的方式做事,你会最快乐。

    【讨论】:

    • 我更喜欢 Perl 或 sed,因为那是我习惯的。虽然编辑大文件有一定的满足感,但我保证会学习 SQL 命令。
    • 后处理是个坏主意,除非您真的确定您完全了解数据是如何转义的,以及如何编写代码来处理它。否则你会损坏你的数据。
    • 如果您确定不会损坏数据,这里有一个示例命令来拆分插入 mysqldump -udbuser dbname | sed 's/),(/),\n(/g' > dump.sql
    • @Tamlyn 但是如果我在 VARCHAR 字段中有),( 怎么办?也许是逗号分隔的表情符号列表,或其他东西。我想,是的...如果您对自己的数据足够了解,那么您就不可能拥有类似的东西...
    • 最好发布 Python 解决方案或链接,而不仅仅是 Python 主页。以前没有听说过 Python 的人,在编写合适的后处理脚本之前还有很长的路要走。
    猜你喜欢
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 2012-02-23
    相关资源
    最近更新 更多