Почему использование bin2hex при вставке двоичных данных от PHP в MySQL?

Я слышал слух, что при вставке двоичных данных (файлы и такой) в MySQL, необходимо использовать bin2hex() функционируйте и отправьте его как КОДИРОВАННОЕ ШЕСТНАДЦАТЕРИЧНЫМИ ЧИСЛАМИ значение, вместо того, чтобы просто используйте 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 обрабатывает большие строки по сравнению с тем, как он обрабатывает КОДИРОВАННЫЕ ШЕСТНАДЦАТЕРИЧНЫМИ ЧИСЛАМИ значения

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

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

Private Bytes used by the mysqld process
(источник: advefir.com)

У кого-либо есть какой-либо explainations или reasources, который разъяснил бы это?

Спасибо.

12
задан Glorfindel 10 July 2019 в 16:05
поделиться

3 ответа

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

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 , или даже если учесть, что операция не выполняет никаких других преобразований, кроме перечисленных выше) было бы совершенно бессмысленно выполнять такую ​​дорогостоящую операцию.

9
ответ дан 2 December 2019 в 19:31
поделиться

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

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

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

4
ответ дан 2 December 2019 в 19:31
поделиться

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

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

  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 в 2-8 раз быстрее, чем в InnoDB. Кажется, что разница в двоичных строках больше, чем в строках с шестнадцатеричным кодом. (См. Данные ниже)
  • При использовании строки в шестнадцатеричном коде ( 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) машина.

5
ответ дан 2 December 2019 в 19:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: