Подтвердить что ты не робот

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

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

Когда я запускаю этот запрос в MySQL CLI (на том же компьютере, на котором запущен PHP script), он занимает 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, который я пробовал, запускал его почти мгновенно, но здесь EXPLAIN для ударов:

+----+-------------+-------+--------+-------------------------+------------+---------+-----------------------------------+------+-------------+
| 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 секунды?

EDIT: Как указано в комментариях, я написал также версию mysql_query, и она имеет такую ​​же плохую производительность. Однако удаление части предложения WHERE заставляет его работать так же быстро, как клиент MySQL. Читайте дальше для ошеломляющих деталей.

4b9b3361

Ответ 1

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

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

Решение в этом (непонятном) случае - использовать подсказку индекса. См. Строку "FROM" в этом модифицированном запросе из моего примера:

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;

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

UTF-8 vs Latin1 mysql, индексы, не используемые на utf-8

Дополнительная информация