Підключення до MySQL від PHP надзвичайно повільне


19

Я щойно зробив нову установку 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


EDIT: Після закінчення часу виявляється, що функція підключення триває так довго:

$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 Workbench підключаються миттєво


php -m вихід будь ласка
thinice

Відповіді:


17

Можливо, ваш mysql намагається запускати rev-dns-запит, коли ви підключаєтесь? спробуйте додати до my.cnf, розділ mysqld: пропустити-ім'я-рішення .


Як не дивно, і PHPMyAdmin, і клієнт MySQL CLI тепер дає мені "Host '127.0.0.1' заборонено підключатися до цього MySQL-сервера". Чомусь сценарій PHP все ще працює, але так само повільно, як і раніше
Hubro

чи "повільні програми" для управління mysql - як mysql workbench - так повільні?
pQd

Запуск того ж запиту від MySQL Workbench проходить так само швидко, як і клієнт CLI, і HeidiSQL
Hubro

додайте трохи часу в php і перевірте, чи це підключення або виконання запиту, що займає багато часу.
pQd

Дякую за цей коментар, я оновив своє запитання. І зв'язок, і запит дуже швидкий
Hubro

30

Це було взято майже дослівно з моєї відповіді тут , але я знаю, що ми нахмурилися на відповіді, що стосуються лише посилань, так що я думаю, що ви теж зробите :-)

Якщо у вас є ця проблема і ви використовуєте версію Windows до Windows 7, це, мабуть, не є відповіддю на вашу проблему.

Чому це відбувається?

Причиною цієї проблеми є IPv4 проти IPv6.

При використанні імені хоста замість IP - адреси клієнт MySQL першим запускає AAAA(IPv6) пошук хоста для імені, і намагається цю адресу першої , якщо вона успішно вирішує ім'я на адресу IPv6. Якщо будь-який крок не вдається (дозвіл імені або з'єднання), він повернеться до IPv4, запустивши Aпошук і замість цього спробуйте цей хост.

Це означає на практиці, що якщо localhostпошук IPv6 успішний, але MySQL не пов'язаний із зворотним зв'язком IPv6, вам доведеться зачекати один цикл очікування підключення до того, як відбудеться падіння IPv4 і успішне з'єднання.

Це не було проблемою до Windows 7, тому що localhostвирішення було виконано за допомогою файлу хостів, і він був попередньо налаштований лише для цього 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.

Чи потрібно змінювати файл хостів?

НІ . Не змінюйте файл хостів. Резолютор DNS знає, що з цим робити localhost, перевизначення цього в кращому випадку не матиме ефекту, а в гіршому випадку переплутає пекло з резолюції.

Про що --skip-name-resolve?

Це також може вирішити проблему з пов’язаної, але трохи іншої причини.

Без цього параметра налаштування MySQL намагатиметься вирішити всі IP-адреси підключення клієнта до імені хоста за допомогою PTRDNS-запиту. Якщо ваш сервер MySQL вже ввімкнено для використання IPv6, але підключення все ще тривалий час, можливо, тому, що зворотний запис DNS ( PTR) неправильно налаштований.

Якщо вимкнути дозвіл імен, виправите цю проблему, але вона має інші наслідки, зокрема, що будь-які дозволи доступу, налаштовані для використання імені DNS в Hostумові, зараз не вдасться.

Якщо ви збираєтесь це робити, вам потрібно буде налаштувати всі свої гранти для використання IP-адрес замість імен.


2
Нарешті! Дякую дякую! Нарешті я знайшов правильне, повне і чітке пояснення всіх причин, можливих рішень та їх протипоказань. Ви повинні написати про це книгу!
tobia.zanarella

4
У мене була затримка на 1 секунду підключення до MySQL на localhost, поки я не змінив bind-address на ::1. На жаль, ::ffff:127.0.0.1продовжував давати мені затримку на 1 секунду (незалежно від використання skip-name-resolveчи ні), будь-які ідеї, чому? (на Windows 8.1)
Simon East

1
@Simon Не поняття, не дивлячись, але першим кроком до налагодження було б спробувати підключитися як до петлі IPv6, так і до петлі IPv4 безпосередньо, використовуючи явні адреси, щоб переконатися, що MySQL насправді слухає та підключається в обох стеках, і налагодження звідти .
DaveRandom

1
так, :: ffff: 127.0.0.1 не працює ...
Raheel Hasan

Якщо я пов'язую його з :: 1, Sqlyog не працює ... що робити ??
Рахіль Хасан

13

Зазвичай, коли IPv6 увімкнено в сервері, підключення до MySQL використовуються localhostвкрай повільно.

Зміна адреси сервера mysql в сценарії 127.0.0.1вирішує проблему.


+1 це була правильна відповідь для мене. Я думаю, що в Windows 8 вони перенесли роздільну здатність localhostдо DNS-рішення з тієї причини, що @DaveRandom пов'язується з: serverfault.com/questions/4689/…
wwarren

Це працювало для мене: D
FosAvance

Це може статися для інших серверів, ніж localhost. У мене була така сама проблема затримки для адреси сервера у формі xx.xxxx.xxxxx.xxxxx.com. Як тільки я змінив ім’я сервера на його IP-адресу, проблеми не було.
Грубер

1
mysql_connect("localhost", "root", "");

Ну, цілком очевидно, в чому причина. PHP справді хороший у деяких речах, але не безпосередньо перекладаючи "localhost" на "127.0.0.1". Потрібно спробувати це, це дійсно знизить загальний час завантаження сторінки веб-сайту, оскільки це стримує PHP від ​​перевірки файлу HOSTS, а що не робиться, щоб отримати справжню IP-адресу за "localhost"


Я не можу зрозуміти, у чому ти намагаєшся запропонувати проблему.
kasperd

@kasperd DNS вирішення 'localhost'
Xesau

Примітка від '17 - функції mysql_ * тепер застарілі та видалені в php7
treyBake


0

Ви також можете усунути уповільнення запитів, зробивши невелике налаштування змінної вашого db-з'єднання (яка, сподіваємось, є окремим файлом із ваших сценаріїв для переносимості). Змініть значення хосту на "127.0.0.1" замість "localhost". Це обходить тривалий пошук DNS для localhost.

Сподіваюся, це допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.