Я разрабатываю приложение 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);