Запросы MySQL в PHP выполняются медленно, когда они выполняются как подготовленные операторы в коде, но быстро выполняются через прямые запросы MySQL. - PullRequest
0 голосов
/ 30 июня 2019

PHP-приложение, которое я пытаюсь отладить, запускает несколько плохо спроектированных запросов в большую базу данных MySQL.

Несколько страниц работают очень медленно, и оказалось, что это из-за нескольких запросов.Я начал проверять каждый запрос один за другим, и хотя они медленные, они не такие медленные сами по себе.

После некоторой дальнейшей отладки оказалось, что они медленные, только когда они выполняются приложением какподготовленные операторы.

  • Если я выполняю запрос вручную через клиент MySQL, это занимает около 300 мс.Если я запускаю создание подготовленного оператора через клиент MySQL, задаю параметры и запускаю его, это занимает около 300 мс.
  • Если я запускаю простой запрос из PHP (mysqli), это занимает около 300 мс.
  • Если я запускаю его так, как приложение - через mysqli - как подготовленное утверждение, это займет 100 секунд.

Я подумал, может быть, это mysqli, поэтому я попыталсяэто с PDO, результат тот же.Пробовал разные версии PHP (5.6, 7.2, 7.3) и получал один и тот же результат.

Так что я дал последний шанс и написал небольшой скрипт Go для тестирования, и я получил те же результаты и вещи улучшились.

Теперь, если я запускаю подготовленную версию оператора запроса от клиента MySQL или MySQL Workbench или клиента базы данных PHPStorms, это быстро.И если я запускаю запрос из кода, он чертовски быстр.

Любая помощь будет очень благодарна за то, что я должен смотреть, где я должен продолжить отладку.

1 Ответ

2 голосов
/ 01 июля 2019

Итак, как оказалось, это было вызвано немного другим планом выполнения. MySQL, похоже, создает план выполнения исключительно на основе оператора, не включая значения параметров при использовании подготовленных операторов с помощью mysqli или PDO, что имеет смысл. Однако, когда ему предоставляется полный запрос, в нашем случае он внедрил оптимизацию для одной из таблиц, что имело огромное значение.

В одной из таблиц (с 5,5 миллионами строк) было указано значение Using join buffer (Block Nested Loop) Extra при работе с неподготовленным оператором, а с подготовленным оператором - нет. Похоже, что это повлияло на производительность почти в 1000 раз.

Я до сих пор не уверен, почему это не имеет проблемы с помощью PHPStorm или клиента CLI mysql, я думаю, что некоторые API в MySQL ожидают, что план выполнения будет завершен при подготовке оператора, в то время как другие API и клиент CLI этого не делает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...