Чтение 65к строк зависает PHP/MySQL
Я разрабатываю приложение PHP, которое обрабатывает IP-адреса. Я работаю с таблицами mysql, содержащими до 4 миллиардов строк.
У меня есть сценарий, который в настоящее время должен получить 65536 адресов из этой таблицы, и интерфейс mysql<->php не может дать ответ через PHP или даже через phpMyAdmin, когда я пытаюсь извлечь эти 65K строк. При использовании в командной строке mysql выдаст 65 тыс. Строк без проблем примерно через 0, 2 с.
Таблица, содержащая IP-адреса, имеет 3 индекса (1 уникальный, 2 основных), которые должны помочь ей ускориться, но я просто не могу заставить MySQL вернуть ассоциативный массив обратно в PHP, чтобы продолжить обработку данных.
Сервер - это недавно выделенный компьютер Xeon с объемом памяти около 32 ГБ (я не знаю точных характеристик).
Любые подсказки о том, что здесь может происходить?
Заранее спасибо.
1 ответ
mysqli
а также PDO
оба работают в режиме буферизации по умолчанию. Это означает, что ваши запросы фактически подчиняются пределу памяти процесса PHP.
С http://php.net/manual/en/mysqlinfo.concepts.buffering.php:
[В режиме с буферизацией] результаты запроса немедленно передаются с MySQL Server на PHP и затем сохраняются в памяти процесса PHP. Это позволяет выполнять дополнительные операции, такие как подсчет количества строк и перемещение (поиск) указателя текущего результата. Это также позволяет выдавать дополнительные запросы по тому же соединению при работе с набором результатов. Недостатком буферизованного режима является то, что для больших наборов результатов может потребоваться достаточно много памяти.
Вы должны либо увеличить лимит памяти процессов PHP в вашем php.ini
увеличивая memory_limit
или вы можете указать запросам использовать небуферизованный режим:
Небуферизованные запросы MySQL выполняют запрос и затем возвращают ресурс, пока данные все еще ожидают на сервере MySQL для извлечения. Это использует меньше памяти на стороне PHP, но может увеличить нагрузку на сервер.
Mysqli пример:
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
$uresult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);
Пример PDO:
$pdo = new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_pass');
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);