Я слышал слухи о том, что при вставке двоичных данных (файлов и т. Д.) В 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-кода
Однако мне сложно это подтвердить. Все мои тесты указывают на точный oposite; что метод bin2hex
~ на 85% медленнее и использует на 24% больше памяти.
(Я тестирую это на PHP 5.3, MySQL 5.1, Win7 x64 – Использование простейшего простого цикла вставки).
Например, на этом графике показано использование частной памяти в процессе mysqld во время работы тестового кода:
Частные байты, используемые процессом mysqld http://img.ruphp.com/binary/priv_mem_cropped.gif
Есть ли у кого-нибудь какие-либо объяснения или объяснения, которые могли бы прояснить это?
Благодарю.
Для меня это звучит как городская легенда.
bin2hex()
отображает каждый байт на вход в два байта на выходе ( 'a'
-> '61'
), поэтому вы должны заметить значительное увеличение памяти скрипта, выполняющего запрос, – он должен использовать по меньшей мере столько же памяти больше как длина байта двоичных данных, подлежащих вставке.
Кроме того, это означает, что запуск bin2hex()
в длинной строке занимает намного больше времени, чем запуск mysql_real_escape string()
, который, как объясняется в документации MySQL, просто ускользает от 6 символов: NULL
, \r
, \n
, \
,
и and Control -Z».
Это было для части PHP, теперь для MySQL: серверу нужно выполнить обратную операцию для правильного хранения данных. Реверсирование любой из функций занимает почти столько же времени, сколько и исходная операция – обратная функция mysql_real_escape_string()
требует замены экранированных значений ( \\
) неэкранированными ( \
), тогда как обратная bin2hex()
должна будет заменить каждый и каждый байтовый кортеж с новым байтом.
Поскольку вызов mysql_real_escape_string()
для двоичных данных является безопасным (согласно документации MySQL и PHP или даже если просто считать, что операция не делает никаких других преобразований, кроме перечисленных выше), было бы совершенно бессмысленно выполнять такую дорогостоящую операцию ,
Я сам тестировал это, и я придумал довольно последовательные результаты. (Хотя мои тесты немного грубые).
Я проверил три компьютера
Пока тесты на всех трех платформах показали одинаковые тона:
bin2hex
в X'...'
) использует в среднем больше памяти, чем использование двоичной строки с экранированием ( mysql_real_escape_string
по необработанным данным) . – Это похоже на MyISAM и InnoDB. Тест был в основном простой петлей, которая избегала или кодировала необработанные данные (изображение 2,4 MiB, полученное один раз в начале скрипта) , построило строку запроса и выполнило ее через функции mysql_query
или mysqli::query
. – Я тестировал оба расширения. Кажется, не было никакой разницы.
Я положил результаты из Ubuntu 10.04 (# 3) в электронные таблицы. Результаты от машины Ubuntu 9.10 (# 2) были почти такими же, поэтому я не стал их настраивать:
(Наконец, оправдание для проверки правильности документов Google! XD)
Эти графики показывают использование частной памяти процессом mysqld
на машине Win7 (# 1).
Шестнадцатеричная строка значительно длиннее соответствующей двоичной строки. Просто время передачи и копирование его внутри памяти PHP и MySQL могут сделать трюк.
Честно говоря, я не эксперт по базовой реализации, но не лучше ли вообще не передавать данные внутри SQL, но используя, например, PDOStatement
параметров PDOStatement
? Может быть, кто-то более осведомленный здесь может подтвердить, действительно ли это приведет к отправке данных как двоичной строки, вне любой инструкции SQL, или же PDO просто выполняет манипуляции с экранированием и строкой запроса под капотом.
В любом случае, вы получаете право на безопасность (и простоту) прямо там.
например, если вы столкнулись с аналогичной проблемой, описанной здесь: http://www.php.net/manual/en/function.mysql-real-escape-string.php#82015
например, хотя mysql_real_escape_string кажется «двоично-безопасным», вы не можете его использовать (в качестве примера) в сочетании с igbinary_serialize – неэрициализация просто завершится неудачей.
в этом случае вам нужно bin2hex перед вставкой данных в mysql.
Кроме того, обычно вы чаще читаете данные из mysql, чем вставляете 🙂