mysqldump可靠地处理二进制数据吗?

Fra*_*ozo 20 mysql mysqldump binary-data

我在MySQL 5.6中有一些表在某些字段中包含大型二进制数据.我想知道我是否可以信任创建的转储,mysqldump并确保在通过FTP,SCP等系统传输转储文件时,这些二进制字段不会轻易损坏.另外,我是否应该强制此类系统将转储文件视为二进制传输而不是ascii?

提前感谢您的任何意见!

Cod*_*tor 36

不,当你有二进制blob时,它并不总是可靠的.在这种情况下,你必须使用" --hex-blob "标志来获得正确的结果.

我有一个案例,这些调用失败(在不同的服务器上导入,但都运行Centos6/MariaDB 10):

mysqldump --single-transaction --routines --databases myalarm -uroot -p"PASSWORD" | gzip > /FILENAME.sql.gz
gunzip < FILENAME.sql.gz | mysql -p"PASSWORD" -uroot --comments
Run Code Online (Sandbox Code Playgroud)

它会生成一个无提示无法导入的文件.添加"--skip-extended-insert"为我提供了一个更容易调试的文件,我发现这行已生成但无法读取(但导出或导入时没有报告错误):

INSERT INTO `panels` VALUES (1003,1,257126,141,6562,1,88891,'??\\\??eV???,NULL);
Run Code Online (Sandbox Code Playgroud)

请注意,原始文件中缺少二进制数据的终止引号.

select hex(packet_key) from panels where id=1003;
--> DE77CF5C075CE002C596176556AAF9ED
Run Code Online (Sandbox Code Playgroud)

该列是二进制数据:

CREATE TABLE `panels` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `enabled` tinyint(1) NOT NULL DEFAULT '1',
  `serial_number` int(10) unsigned NOT NULL,
  `panel_types_id` int(11) NOT NULL,
  `all_panels_id` int(11) NOT NULL,
  `installers_id` int(11) DEFAULT NULL,
  `users_id` int(11) DEFAULT NULL,
  `packet_key` binary(16) NOT NULL,
  `user_deleted` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  ...
Run Code Online (Sandbox Code Playgroud)

所以不,你不仅不一定信任mysqldump,你甚至不能依赖它来报告错误.


我使用的一个丑陋的解决方法是mysqldump通过向转储中添加这样的选项来排除两个受影响的表:

--ignore-table=myalarm.panels 
Run Code Online (Sandbox Code Playgroud)

然后这个BASH脚本破解.基本上运行一个SELECT,它产生INSERT值,其中处理NULL列,二进制列变成UNHEX()调用,如下所示:

(123,45678,UNHEX("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),"2014-03-17 00:00:00",NULL),
Run Code Online (Sandbox Code Playgroud)

如果需要,将其粘贴到您选择的编辑器中以进行播放.

echo "SET UNIQUE_CHECKS=0;SET FOREIGN_KEY_CHECKS=0;DELETE FROM panels;INSERT INTO panels VALUES " > all.sql
mysql -uroot -p"PASSWORD" databasename -e "SELECT CONCAT('(',id,',', enabled,',', serial_number,',', panel_types_id,',', all_panels_id,',', IFNULL(CONVERT(installers_id,CHAR(20)),'NULL'),',', IFNULL(CONVERT(users_id,CHAR(20)),'NULL'), ',UNHEX(\"',HEX(packet_key),'\"),', IF(ISNULL(user_deleted),'NULL',CONCAT('\"', user_deleted,'\"')),'),') FROM panels" >> all.sql
echo "SET UNIQUE_CHECKS=1;SET FOREIGN_KEY_CHECKS=1;" > all.sql
Run Code Online (Sandbox Code Playgroud)

这给了我一个名为"all.sql"的文件,它需要INSERT中的最后一个逗号变为分号,然后它可以像上面那样运行.我需要在交互式mysql shell和命令行中设置"大导入缓冲区"调整来处理该文件,因为它很大.

mysql ... --max_allowed_packet=1GB
Run Code Online (Sandbox Code Playgroud)

当我报告这个错误时,我最终指向了"--hex-blob"标志,这与我的解决方法一样,但是从我的方面来说是微不足道的.添加该选项,blob将以十六进制形式转储,结束.

  • 请注意,尽管我尝试重新打开该错误,但两年后该错误仍被标记为“不能重复”,而且 MySQL 人员似乎并不倾向于修复它。 (2认同)

Gus*_*Gil 7

生成的转储mysqldump可以信任.

为避免编码,二进制传输等问题,请使用该--hex-blob选项,以便将每个字节转换为十六进制数(例如,'abc'变为0x616263).它将使转储更大,但它将是获得信息的最兼容和安全的方式(因为它将是纯文本,由于文本文件上的二进制数据生成的特殊符号,没有奇怪的误解).

您可以确保将其打包在rar或zip文件中的转储文件的完整性(并加快传输速度).通过这种方式,您可以轻松检测到它没有被传输损坏.

当您尝试在服务器上加载它时,请检查您是否已在my.cnf服务器配置文件中分配

[mysqld]
max_allowed_packet=600M
Run Code Online (Sandbox Code Playgroud)

或者更多,如果需要.

BTW现在我刚刚进行了一次迁移,并抛弃了大量的二进制数据mysqldump并且工作得很好.

  • MySQL团队对上述错误的反应是"不会修复,使用--hex-blob解决方法",所以这似乎是最好的解决方案. (2认同)