Зачем использовать bin2hex при вставке двоичных данных из PHP в MySQL? - PullRequest
12 голосов
/ 01 апреля 2010

Я слышал слух, что при вставке двоичных данных (файлов и тому подобное) в 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}')";

Это предположительно из соображений производительности. Как-то связано с тем, как MySQL обрабатывает большие строки, и с тем, как он обрабатывает HEX-кодированные значения

Однако мне трудно это подтвердить. Все мои тесты показывают точный опозит; что метод bin2hex медленнее на 85% и использует на 24% больше памяти.
(я тестирую это на PHP 5.3, MySQL 5.1, Win7 x64 - используя очень простой цикл вставки.)

Например, на этом графике показано использование личной памяти процесса mysqld во время выполнения тестового кода:

Частные байты, используемые процессом mysqld http://atli.advefir.com/images/priv_mem_cropped.gif

Есть ли у кого-нибудь какие-либо объяснения или источники, которые бы прояснили это?

Спасибо.

Ответы [ 4 ]

9 голосов
/ 10 апреля 2010

Для меня это звучит как городская легенда.

bin2hex() отображает каждый байт на входе в два байта на выходе ('a' -> '61'), поэтому вы должны заметить значительное увеличение памяти скрипта, выполняющего запрос - он должен использовать как минимум столько же памяти, сколько длина байта вставляемых двоичных данных.

Кроме того, это означает, что выполнение bin2hex() на длинной строке занимает намного дольше, чем выполнение mysql_real_escape string(), что - как объяснено в документации MySQL - просто экранирует 6 символов: NULL, \r, \n, \, , и 'Control-Z'.

Это было для части PHP, теперь для MySQL: серверу необходимо выполнить обратную операцию для правильного хранения данных. Обращение любой из функций занимает почти столько же времени, сколько и в исходной операции - функция обратного хода mysql_real_escape_string() должна заменить экранированные значения (\\) на неэкранированные (\), тогда как обратное значение bin2hex() должно замените каждый байтный кортеж новым байтом.

Поскольку вызов mysql_real_escape_string() для двоичных данных является безопасным (в соответствии с документацией MySQL и PHP или даже с учетом того, что операция не выполняет никаких других преобразований, кроме перечисленных выше), она может сделать Совершенно бессмысленно выполнять такую ​​дорогостоящую операцию.

5 голосов
/ 03 апреля 2010

Я сам проверял это и получил довольно последовательные результаты. (хотя мои тесты немного сыры.)

Я проверил три компьютера

  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

До сих пор тесты на всех трех платформах указывали на одно и то же:

  • Вставка в BLOB в 2-8 раз быстрее в MyISAM, чем в InnoDB. Разница в бинарных строках выше, чем в шестнадцатеричном коде. (см. Данные ниже)
  • Использование HEX-кодированной строки (bin2hex в X'...') в среднем использует больше памяти, чем использование экранированной двоичной строки (mysql_real_escape_string в необработанных данных) . - Это похоже на MyISAM и InnoDB.
  • Двоичная строка быстрее в MyISAM, но HEX-кодированные данные быстрее в InnoDB.

Тест был в основном простым циклом, который экранировал или кодировал шестнадцатеричные исходные данные (изображение размером 2,4 МБ, полученное один раз в верхней части скрипта) , построил строку запроса и выполнил ее функции mysql_query или mysqli::query. - Я тестировал оба расширения. Похоже, не было никакой разницы.

Я поместил результаты Ubuntu 10.04 (# 3) в электронные таблицы. Результаты на машине с Ubuntu 9.10 (# 2) были почти такими же, поэтому я не стал их настраивать:
(наконец, оправдание для правильной проверки Google Docs! XD)

Эти графики показывают использование частной памяти процессом mysqld на компьютере с Win7 (# 1).

4 голосов
/ 01 апреля 2010

Шестнадцатеричная строка значительно длиннее соответствующей двоичной строки. Просто время переноса и его копирование в памяти PHP и MySQL может помочь.

Честно говоря, я не специалист по базовой реализации, но не лучше ли вообще не передавать данные в SQL, а использовать, например, PDOStatement привязка параметров? Может быть, кто-то более осведомленный здесь может подтвердить, действительно ли это приведет к отправке данных в виде двоичной строки, вне какого-либо оператора SQL вообще, или же PDO просто выполняет экранирование и манипулирование строкой запроса изнутри.

В любом случае, вы сразу получаете выгоду безопасности (и простоты).

0 голосов
/ 12 апреля 2012

например, если вы столкнулись с подобной проблемой, как описано здесь: http://www.php.net/manual/en/function.mysql-real-escape-string.php#82015

например. хотя mysql_real_escape_string кажется «бинарно-безопасным», вы не можете использовать его (в качестве примера) в сочетании с igbinary_serialize - десериализация просто не удастся.

в этом случае вам необходимо выполнить bin2hex до вставки данных в mysql.

Кроме того, обычно вы чаще читаете данные из mysql, чем вставляете:)

...