28.11. Повышение скорости обработки запросов СУБД MySQL
Функция mysql_query, вероятно, самая популярная в PHP. Являясь пользователем MySQL, вы постоянно используете ее для отправки запросов к серверу MySQL, получая в ответ результирующие наборы. Но, возможно, вы не знаете, что при возвращении больших результирующих наборов или при запросах к большим базам данных функция mysql_query может работать очень неэффективно.
Для того чтобы разобраться в причинах этой неэффективности, необходимо понимать, как работает функция mysql_query. При выдаче запроса SELECT с помощью функции mysql_query PHP отправляет его на сервер MySQL, который анализирует его, создает план выполнения и начинает итерации по строкам таблицы в поиске соответствующих результатов. При каждом нахождении соответствующего результата сервер отсылает его назад по сети клиенту. На стороне клиента PHP присоединяет каждую строку в буфер до тех пор, пока сервер не отправит сообщение с подтверждением того, что больше строк не осталось. Когда это происходит, функция mysql_query возвращает управление приложению PHP и разрешает осуществить итерации по результату, расположенному в буфере.
Проблема производительности возникает тогда, когда мы сталкиваемся с большими результирующими наборами или когда осуществляется запрос к очень большим базам данных. В таких случаях время, прошедшее с момента получения первой результирующей и последней результирующей строки, может быть достаточно продолжительным. Даже если клиент ничего не делает, в этот момент начать обработку результатов невозможно. Необходимо выждать до тех пор, пока сервер не отправит самую последнюю строку, и только после этого управление будет возвращено пользователю, и он сможет приступить к обработке результатов. А хотелось бы приступать к обработке результирующих строк по мере их поступления, так как это позволило бы увеличить быстродействие. И, как всегда, PHP не разочарует вас.
Кроме функции mysql_query, PHP предлагает дополнительную версию этой функции - mysql_unbuffered_query. API-интерфейс для обеих функций идентичный, но функция mysql_unbuffered_query не буферизирует результирующие строки перед передачей управления PHP-приложению. Вместо этого он возвращает управление PHP сразу же после выдачи запроса. Каждый раз, когда мы выбираем строку, модуль MySQL пытается прочесть следующую строку с сервера и возвращает управление приложению сразу же после выборки строки. Таким образом, появляется возможность обработки строк по мере их появления, не ожидая, когда будет получен весь результирующий набор.
Но если небуферизируемые запросы такие замечательные, то почему PHP разрешает использовать обычные буферизируемые запросы? К сожалению, на то есть своя причина, заключающаяся в том, что небуферизируемые запросы - не всегда лучший выход. Если сервер отправляет строки быстрее, чем клиент может прочесть их, сервер блокирует соответствующие таблицы больше времени, чем это необходимо. Операторы SQL, предназначенные для записи в эту таблицу, ожидают, пока операция чтения не будет за­вершена. Это может привести к существенному снижению производительности для страниц, которые производят изменения в базе данных. Поэтому использование небу-феризируемых запросов рекомендуется только тогда, когда общее количество клиентов, работающих с данной страницей, мало или обновления происходят нечасто.