Подключение к MySQL из PHP очень медленное
Я только что сделал новую установку XAMPP. При первом открытии PHPMyAdmin я заметил, что это было очень медленно. Не имеет смысла, что на localhost для открытия каждой страницы требуется почти 5 секунд. Я сделал небольшой тестовый пример, чтобы снять вину с PHPMyAdmin:
$con = new PDO("mysql:host=localhost;dbname=mysql", "root", "");
$statement = $con->query('SELECT host,user,password FROM user;');
$users = $statement->fetchAll(PDO::FETCH_ASSOC);
Вышеприведенный скрипт запускается всего за 3 секунды (хотя при первой его загрузке потребовалось около 8 секунд).
Затем, чтобы проверить, была ли это ошибка PDO, я попытался использовать mysql_connect
вместо:
$con = mysql_connect("localhost", "root", "");
mysql_select_db("mysql", $con);
$result = mysql_query('SELECT host,user,password FROM user;');
Требуется ровно столько времени, чтобы закончить.
Сначала я думал, что это вина PHP, но PHP-код и статические файлы обслуживаются быстрее, чем я могу нажать обновить. Я проверил PHP, запустив этот маленький скрипт:
header("Content-Type: text/plain");
for($i = 0; $i < 5000; $i++)
{
echo sha1(rand()) . "\n";
}
5000 sha1
расчеты и страница по-прежнему отображается быстрее, чем я могу обновить свое окно.
Тогда я решил, что это вина MySQL. Но опять же, не нужно было много тестировать, чтобы понять, что MySQL работает быстрее, чем мне нужно. Используя клиентский интерфейс MySQL CLI, пользовательский запрос на выборку даже не занимает измеримое время - он выполняется еще до того, как я позволил ключу возврата вернуться вверх.
Проблема должна быть связана с подключением PHP к MySQL - насколько я могу судить. Я могу найти тонны вещей о медленном PHP или медленном MySQL, но ничего о PHP+MySQL очень медленном.
Спасибо всем, кто может помочь мне решить эту проблему!
Я использую XAMPP 1.8.0 для win32 ( ссылка на скачивание)
Версия PHP: 5.4.4
Версия MySQL: 14.14
РЕДАКТИРОВАТЬ: после синхронизации оказывается, что это функция подключения, которая занимает так много времени:
$time = microtime(true);
$con = mysql_connect("localhost", "root", "");
mysql_select_db("mysql", $con);
$con_time = microtime(true);
$result = mysql_query('SELECT host,user,password FROM user;');
$sel_time = microtime(true);
printf("Connect time: %f\nQuery time: %f\n",
$con_time-$time,
$sel_time-$con_time);
Выход:
Время подключения: 1.006148 Время запроса: 0.000247
Что может заставить PHP тратить много времени на подключение к базе данных? Клиент CLI, рабочая среда HeidiSQL и MySQL подключаются мгновенно
6 ответов
Может быть, ваш mysql пытается выполнить запрос rev-dns при каждом подключении? попробуйте добавить в my.cnf раздел mysqld: skip-name-Resolution.
Это почти дословно взято из моего ответа здесь, но я знаю, что мы недовольны ответами только для ссылок на SO, так что я думаю, что вы, ребята, тоже так делаете:-)
Если у вас возникла эта проблема и вы используете версию Windows до Windows 7, это, вероятно, не ответ на вашу проблему.
Почему это происходит?
Причиной этой проблемы является IPv4 против IPv6.
Когда вы используете имя хоста вместо IP-адреса, клиент MySQL сначала запускает AAAA
(IPv6) хост ищет имя и сначала пробует этот адрес, если он успешно разрешает имя в адрес IPv6. Если какой-либо шаг не удался (разрешение имени или соединение), он переключится на IPv4, запустив A
искать и пробовать этот хост вместо этого.
На практике это означает, что если IPv6 localhost
поиск выполнен успешно, но MySQL не связан с обратной связью IPv6, вам нужно будет подождать один цикл тайм-аута соединения, прежде чем произойдет откат IPv4 и соединение установится успешно.
Это не было проблемой до Windows 7, потому что localhost
разрешение было сделано через файл hosts, и оно было предварительно настроено только с 127.0.0.1
- это не идет с его аналогом IPv6 ::1
,
С Windows 7, однако, localhost
Разрешение встроено в преобразователь DNS по причинам, изложенным здесь. Это означает, что поиск IPv6 теперь будет успешным, но MySQL не привязан к этому IPv6-адресу, поэтому соединение не будет установлено, и вы увидите задержку, описанную в этом вопросе.
Это мило. Просто скажи мне, как это исправить уже!
У вас есть несколько вариантов. Оглядываясь в Интернете, можно сказать, что общим "решением" является явное использование IP-адреса вместо имени, но есть несколько причин не делать этого, обе связаны с переносимостью, обе, возможно, не важны:
Если вы переместите свой скрипт на другой компьютер, который поддерживает только IPv6, ваш скрипт больше не будет работать.
Если вы переместите свой скрипт в среду размещения * nix, волшебная строка
localhost
будет означать, что клиент MySQL предпочтет использовать сокет Unix, если он настроен, это более эффективно, чем возможность подключения по IP-шлейфу
Они звучат довольно важно, хотя?
Это не так. Вы должны разрабатывать свое приложение так, чтобы такого рода вещи определялись в файле конфигурации. Если вы переместите свой сценарий в другую среду, скорее всего, другие вещи также потребуются в настройке.
Таким образом, использование IP-адреса не является лучшим решением, но, скорее всего, приемлемым.
Так какое же самое лучшее решение?
Лучшим способом было бы изменить адрес привязки, который использует сервер MySQL. Однако это не так просто, как хотелось бы. В отличие от Apache, Nginx и почти любого другого приложения для работы с сетевыми службами, MySQL поддерживает только один адрес привязки, поэтому это не просто случай добавления другого. К счастью, операционные системы поддерживают магию, поэтому мы можем позволить MySQL одновременно использовать как IPv4, так и IPv6.
Вам нужно запустить MySQL 5.5.3 или новее, и вам нужно запустить MySQL с --bind-address=
аргумент командной строки. У вас есть 4 варианта документации, в зависимости от того, что вы хотите сделать:
Тот, с которым вы, вероятно, знакомы, и тот, который вы наиболее вероятно (эффективно) используете,
0.0.0.0
, Это привязывает ко всем доступным IPv4-адресам на машине. На самом деле это, вероятно, не лучшая вещь, даже если вы не заботитесь об IPv6, поскольку он подвержен тем же рискам безопасности, что и::
,Явный адрес IPv4 или IPv6 (например,
127.0.0.1
или же::1
для петли). Это связывает сервер с этим адресом и только с этим адресом.Волшебная струна
::
, Это свяжет MySQL с каждым адресом на машине, как с обратной связью, так и с адресами физического интерфейса, в режимах IPv4 и IPv6. Это потенциально угроза безопасности, делайте это только в том случае, если вам нужен MySQL для приема соединений от удаленных хостов.Используйте IPv4-сопоставленный IPv6-адрес. Это специальный механизм, встроенный в IPv6 для обратной совместимости при переходе 4 -> 6, и он позволяет вам привязываться к определенному адресу IPv4 и его эквиваленту IPv6. Это вряд ли пригодится вам для чего-либо, кроме адреса "двойной петли"
::ffff:127.0.0.1
, Скорее всего, это лучшее решение для большинства людей, связанное только с обратной связью, но допускающее подключения как по IPv4, так и по IPv6.
Нужно ли изменять файл hosts?
№ Не изменяйте файл hosts. DNS-распознаватель знает, что делать с localhost
переопределение его в лучшем случае не будет иметь никакого эффекта, а в худшем - запутает его в решении проблем.
Как насчет --skip-name-resolve
?
Это также может решить проблему по связанной, но немного другой причине.
Без этой опции конфигурации MySQL будет пытаться разрешить все IP-адреса подключения клиента к имени хоста через PTR
DNS-запрос. Если ваш сервер MySQL уже включен для использования IPv6, но соединения по-прежнему занимают много времени, это может быть связано с обратным DNS (PTR
) запись не правильно настроена.
Отключение разрешения имен решит эту проблему, но оно имеет другие последствия, в частности, что любые разрешения на доступ, настроенные для использования DNS-имени в Host
условие теперь не выполнится.
Если вы собираетесь это сделать, вам нужно будет настроить все свои права на использование IP-адресов вместо имен.
Обычно, когда IPv6 включен в соединениях сервера с MySQL, используя localhost
очень медленно.
Изменение адреса сервера mysql в скрипте на 127.0.0.1
решает проблему.
mysql_connect("localhost", "root", "");
Ну, это совершенно очевидно, в чем причина. PHP действительно хорош в некоторых вещах, но не в прямом переводе "localhost" в "127.0.0.1". Вы должны попробовать это, это действительно уменьшит общее время загрузки страницы вашего сайта, потому что он удерживает PHP от проверки вашего файла HOSTS и того, что он не делает, чтобы получить реальный IP-адрес за "localhost"
Добавление этой строки в ваш файл hosts решило проблему для меня
127.0.0.1 localhost
Подробный ответ можно найти в этой теме: https://stackoverflow.com/questions/13584360/php-with-mysql-is-slow
Вы также можете устранить замедление запросов, внеся небольшую корректировку в переменную соединения с БД (которая, мы надеемся, находится в отдельном файле от ваших скриптов для переносимости). Измените значение хоста на "127.0.0.1" вместо "localhost". Это обходит долгий поиск DNS для localhost.
Надеюсь это поможет!