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

为什么在将PHP中的二进制数据插入MySQL时使用bin2hex?,php,mysql,binary,insert,Php,Mysql,Binary,Insert,我听说有传言说,在将二进制数据(文件等)插入MySQL时,应该使用bin2hex()函数并将其作为十六进制编码的值发送,而不是在二进制字符串上使用MySQL\u real\u escape\u string // That you should do $hex = bin2hex($raw_bin); $sql = "INSERT INTO `table`(`file`) VALUES (X'{$hex}')"; // Rather than $bin = mysql_real_escape_

我听说有传言说,在将二进制数据(文件等)插入MySQL时,应该使用
bin2hex()
函数并将其作为十六进制编码的值发送,而不是在二进制字符串上使用
MySQL\u real\u escape\u 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}')";
这应该是出于性能原因。MySQL处理大字符串的方式与处理十六进制编码值的方式有关

然而,我很难证实这一点。我所有的测试都显示了确切的位置;
bin2hex
方法的速度慢了约85%,占用的内存多了约24%。
(我正在PHP5.3、MySQL 5.1、Win7x64上测试这一点——使用非常简单的插入循环。)

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


(来源:)

有人有任何解释或资料可以澄清这一点吗


谢谢。

十六进制字符串比相应的二进制字符串长很多。简单地说,传输时间和在PHP和MySQL内存中复制时间就可以做到这一点

老实说,我不是底层实现方面的专家,但最好不要在SQL内部传递数据,而是使用例如
PDOStatement
的参数绑定?也许这里更了解情况的人可以确认这是否真的会导致数据以二进制字符串的形式发送到任何SQL语句之外,或者PDO是否只是在幕后进行转义和查询字符串操作


无论哪种方式,您都可以从中获得安全性(和简单性)的好处。

我自己也进行了测试,得到了非常一致的结果。(尽管我的测试有点粗糙。)

我测试了三台电脑

  • Windows7(x64)、PHP5.3、MySQL 5.1
  • Ubuntu 9.10(x64)PHP 5.2,MySQL 5.1
  • Ubuntu 10.04(x32)PHP5.3,MySQL 5.1
  • 到目前为止,在所有三个平台上进行的测试都表明了相同的情况:

    • 在MyISAM上插入BLOB比在InnoDB上快2到8倍。二进制字符串上的差异似乎高于十六进制编码字符串。(见以下数据)
    • 使用十六进制编码字符串(
      bin2hex
      X'.'
      )比在原始数据上使用转义二进制字符串(
      mysql\u real\u escape\u string
      )平均占用更多内存这似乎对MyISAM和InnoDB都适用
    • MyISAM上的二进制字符串速度更快,但InnoDB上的十六进制编码数据速度更快

    测试基本上只是一个简单的循环,它对原始数据(在脚本顶部检索一次的2.4 MiB图像)进行转义或十六进制编码,构造查询字符串,并通过
    mysql\u query
    mysqli::query
    函数执行我测试了两个扩展。看起来没什么区别

    我把Ubuntu 10.04(#3)的结果放在电子表格中。Ubuntu9.10(#2)机器的结果几乎相同,所以我没有费心设置它们:
    (最后是正确测试谷歌文档的借口!xD)

    这些图显示了Win7(#1)机器上
    mysqld
    进程的私有内存使用情况


      • 这听起来像是一个城市传奇

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

        此外,这意味着在长字符串上运行
        bin2hex()
        比运行
        mysql\u real\u escape string()
        花费的时间要长得多,正如中所解释的,它只转义6个字符:
        NULL
        \r
        \n
        和“Control-Z”

        这是PHP部分,现在是MySQL:服务器需要执行反向操作来正确存储数据。反转这两个函数所需的时间几乎与原始操作一样长。
        mysql\u real\u escape\u string()
        的反转函数需要将转义值(
        \
        )替换为未转义值(
        \
        ),而
        bin2hex()
        的反转函数需要将每个字节元组替换为新字节


        因为在二进制数据上调用
        mysql\u real\u escape\u string()
        是安全的(根据mysql的,甚至考虑到该操作不会进行上述转换以外的任何其他转换),执行如此昂贵的操作是毫无意义的。

        例如,如果您遇到如下所述的类似问题:

        e、 尽管mysql\u real\u escape\u字符串看起来是“二进制安全的”,但您不能将其(作为示例)与igbinary\u serialize结合使用-非序列化将失败

        在这种情况下,在将数据插入mysql之前,您需要bin2hex


        另外,通常您从mysql读取数据的频率要比插入数据的频率高:)

        谢谢您的回复。这也是我的第一次想法;转换过程和字符串长度的增加会导致性能下降。看来我们是对的然而,我现在发现了几个页面显示了
        bin2hex
        函数的使用(或者更令人不安的是,Base64函数),我看不出原因。这毫无意义……——顺便说一句,就个人而言,我确实使用预先准备好的语句(通常是mysqli)。这个问题更多的是假设性的,而不是实际的:)如果表是(错误地)用文本字段而不是BLOB创建的,那么bin2hex/base64将避免任何字符集问题。但以数据大小增加3倍为代价(假设数据完全非ascii并完全转换为%xx%yy%zz…),十六进制和base64都会增加