为什么在将二进制数据从PHP插入MySQL时使用bin2hex?

Atl*_*tli 12 php mysql binary insert

我听说有传言说在将二进制数据(文件等)插入MySQL时,你应该使用该bin2hex()函数并将其作为HEX编码值发送,而不是仅仅使用mysql_real_escape_string二进制字符串并使用它.

// That you should do
$hex = bin2hex($raw_bin);
$sql = "INSERT INTO `table`(`file`) VALUES (X'{$hex}')";

// Rather than
$bin = mysql_real_escape_string($raw_bin);
$sql = "INSERT INTO `table`(`file`) VALUES ('{$bin}')";
Run Code Online (Sandbox Code Playgroud)

据说这是出于性能原因.与MySQL如何处理大字符串以及如何处理HEX编码值有关

但是,我很难确认这一点.我所有的测试都表明确切的对话; 该bin2hex方法慢了约85%,使用了大约24%的内存.
(我在PHP 5.3,MySQL 5.1,Win7 x64上测试它 - 使用一个简单的插入循环.)

例如,此图显示了测试代码运行时mysqld进程的私有内存使用情况:

mysqld进程使用的私有字节http://atli.advefir.com/images/priv_mem_cropped.gif

有没有人有解释这个的解释或资源?

谢谢.

sou*_*rge 9

这听起来像是我的都市传奇.

bin2hex()将输入中的每个字节映射到输出中的两个字节('a'- > '61'),因此您应该注意到执行查询的脚本会显着增加内存 - 它应该至少使用与二进制数据的字节长度相同的内存量.插入.

此外,这意味着运行bin2hex()在一个长字符串采用比跑步的时间延长mysql_real_escape string(),这-在解释MySQL的文档 -只是逃脱6个字符:NULL,\r,\n,\,,和"控制-Z".

那是PHP部分,现在是MySQL:服务器需要执行相反的操作才能正确存储数据.反转任一函数几乎与原始操作一样长 - mysql_real_escape_string()需要\\用非转义的(\)替换转义值()的反向函数,而反向bin2hex()需要用新字节替换每个字节元组.

由于调用mysql_real_escape_string()二进制数据是安全的(根据MySQL和PHP的文档,或者甚至只考虑操作不会执行上面列出的任何其他转换),执行如此昂贵的操作绝对没有意义.


Atl*_*tli 5

我自己一直在测试,我得出了非常一致的结果.(即使我的测试有点粗糙.)

我测试了三台电脑

  1. Windows 7(x64),PHP 5.3,MySQL 5.1
  2. Ubuntu 9.10(x64)PHP 5.2,MySQL 5.1
  3. Ubuntu 10.04(x32)PHP 5.3,MySQL 5.1

到目前为止,所有三个平台上的测试都表明了相同的情况:

  • 在MyISAM上插入BLOB的速度比在InnoDB上快2到8倍.二进制字符串的差异似乎高于HEX编码的字符串.(见下面的数据)
  • 与使用转义二进制字符串(在原始数据上)相比,使用HEX编码字符串(bin2hex进入a X'...')平均使用更多内存. - MyISAM和InnoDB似乎都是如此.mysql_real_escape_string
  • MyISAM上的二进制字符串更快,但是InnoDB上的HEX编码数据更快.

测试基本上只是一个简单的循环,它对原始数据进行转义或十六进制编码(在脚本顶部检索一次2.4 MiB图像),构造查询字符串,并通过mysql_querymysqli::query函数执行. - 我测试了两个扩展.似乎没有任何区别.

我将Ubuntu 10.04(#3)的结果放在电子表格中.Ubuntu 9.10(#2)机器的结果几乎相同,所以我没有打扰它们:(
最后借口正确测试Google Docs的东西!xD)

这些图表显示了mysqldWin7(#1)计算机上进程的专用内存使用情况.