Назад | Перейти на главную страницу

При чтении 65k строк зависает PHP / MySQL

Я разрабатываю приложение PHP, которое обрабатывает IP-адреса. Я работаю с таблицами mysql, содержащими до 4 миллиардов строк.

У меня есть сценарий, который в настоящее время должен получить 65536 адресов из этой таблицы, а интерфейс mysql <-> php не может дать ответ через PHP или даже через phpMyAdmin, когда я пытаюсь извлечь эти 65K строк. При использовании в командной строке mysql без проблем выдаст 65 КБ строк примерно за 0,2 секунды.

Таблица, содержащая IP-адреса, имеет 3 индекса (1 уникальный, 2 основных), которые должны помочь ему работать быстрее, но я просто не могу отказаться от того, что mysql вернет ассоциативный массив обратно в PHP, чтобы продолжить обработку данных.

Сервер - это недавно выделенная машина Xeon с объемом памяти около 32 ГБ (я не знаю точных характеристик).

Есть какие-нибудь подсказки о том, что здесь может происходить?

Заранее спасибо.

mysqli и PDO оба работают в буферный режим по умолчанию. Это означает, что на ваши запросы действительно распространяется ограничение памяти процесса PHP.

Из http://php.net/manual/en/mysqlinfo.concepts.buffering.php:

[В режиме буферизации] результаты запроса немедленно передаются с сервера MySQL на 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);