PHP выполняет запрос в 90 раз дольше, чем клиент MySQL

Я выполняю запрос MySQL через PHP-скрипт командной строки (подготовленный запрос с использованием PDO на драйвере mysqlnd). Это простой запрос с одним левым соединением, возвращающий 100 строк и 7 маленьких столбцов на строку.

Когда я выполняю этот запрос в интерфейсе командной строки MySQL (на том же компьютере, на котором выполняется рассматриваемый PHP-скрипт), он занимает 0,10 секунды - даже с добавленным флагом SQL_NO_CACHE.

Когда я запускаю этот запрос, подготовленный через PDO, он занимает более 9 секунд. Это только execute() - не включая время, необходимое для вызова выборки.

Пример моего запроса:

SELECT HEX(al.uuid) hexUUID, al.created_on,
    IFNULL(al.state, 'ON') actionType, pp.publishers_id publisher_id,
    pp.products_id product_id, al.action_id, al.last_updated
FROM ActionAPI.actionLists al
LEFT JOIN ActionAPI.publishers_products pp
    ON al.publisher_product_id = pp.id
WHERE (al.test IS NULL OR al.test = 0)
    AND (al.created_on >= :since OR al.last_updated >= :since)
ORDER BY created_on ASC
LIMIT :skip, 100;

Я не верю, что запрос ошибочен, учитывая, что каждый собственный клиент MySQL, который я пробовал, запускал его почти мгновенно, но вот ОБЪЯСНЕНИЕ для ударов:

+----+-------------+-------+--------+-------------------------+------------+---------+-----------------------------------+------+-------------+
| id | select_type | table | type   | possible_keys           | key        | key_len | ref                               | rows | Extra       |
+----+-------------+-------+--------+-------------------------+------------+---------+-----------------------------------+------+-------------+
|  1 | SIMPLE      | al    | index  | created_on,last_updated | created_on | 8       | NULL                              |  100 | Using where |
|  1 | SIMPLE      | pp    | eq_ref | PRIMARY                 | PRIMARY    | 4       | ActionAPI.al.publisher_product_id |    1 |             |
+----+-------------+-------+--------+-------------------------+------------+---------+-----------------------------------+------+-------------+
2 rows in set (0.00 sec)

Что в мире делает PDO, что занимает 8,9 секунды?

РЕДАКТИРОВАТЬ: Как указано в комментариях, я также написал версию mysql_query, и она имеет ту же низкую производительность. Однако удаление части предложения WHERE делает его работающим так же быстро, как клиент MySQL. Продолжайте читать для ошеломляющих деталей.

4 ответа

Решение

Давая очень запоздалое обновление по этому вопросу:

Я не нашел причину, но оказалось, что EXPLAIN отличался в PHP от CLI. Я не уверен, что какой-либо аспект соединения заставит MySQL использовать другое поле для индекса, потому что, насколько я знаю, эти вещи не должны быть связаны; но, увы, EXPLAIN PHP показал, что правильный индекс не использовался, в то время как CLI использовал.

Решение в этом (сбивающем с толку) случае состоит в том, чтобы использовать индексную подсказку. Смотрите строку "ОТ" в этом измененном запросе из моего примера:

SELECT HEX(al.uuid) hexUUID, al.created_on,
    IFNULL(al.state, 'ON') actionType, pp.publishers_id publisher_id,
    pp.products_id product_id, al.action_id, al.last_updated
FROM ActionAPI.actionLists al USE INDEX (created_on)
LEFT JOIN ActionAPI.publishers_products pp
    ON al.publisher_product_id = pp.id
WHERE (al.test IS NULL OR al.test = 0)
    AND (al.created_on >= :since OR al.last_updated >= :since)
ORDER BY created_on ASC
LIMIT :skip, 100;

Надеюсь, это поможет кому-то!

У меня такая же проблема. Один и тот же запрос работал по-разному при запуске из cli и из PHP. Объясните в упомянутом клике правильное использование индекса, в PHP ничего не было. Как я обнаружил, проблема заключалась в приведении типов, в моем случае это была дата и время. После того как у меня есть специально приведенный тип для сравниваемого значения, например. where datetime_column > cast('2014-01-12 12:30:01' as datetime) все работает.

PDO использует ресурсы для манипулирования результатами строк. Сравните это с интерпретированным языком (PHP), и у вас будет скрипт, который обрабатывает больше времени, чем MySQL, чтобы вернуть ваши результаты.

ПРИМЕЧАНИЕ. Использование mysql_select_db() или mysqli_select_db() намного быстрее, чем PDO.

Чтобы узнать больше о более быстрых запросах PHP, см.: PHP: Какой самый быстрый способ запроса MySQL? Потому что PDO мучительно медленный

При подключении в командной строке ОЧЕНЬ вероятно использовать другой набор символов, который используется при подключении с помощью PHP.

Когда вы просите его использовать индекс, он будет и потому, что наборы символов достаточно близки, чтобы не вызывать проблемы (по предположению? Это зависит от ваших настроек таблицы и столбцов).

Попробуйте добавить туда несколько символов Unicode, и они, вероятно, начнут давать плохие результаты.

Убедитесь, что набор символов соответствует соединению, таблице и столбцу для достижения наилучших результатов. Если они не могут быть сделаны, соединение является наиболее важным

UTF-8 против Latin1 mysql, индексы не используются в utf-8

Имеет больше информации

Другие вопросы по тегам