Скорость / наилучшая практика сглаживания mysqli_multi_query ()

Я съежился, когда Себастьян заявил, что он отключает и повторно соединяет между каждым использованием mysqli_multi_query() @ Может ли mysqli_multi_query делать инструкции UPDATE? потому что это просто не казалось лучшей практикой.

Тем не менее, Craig @ mysqli multi_query, за которым следует запрос, заявлял в своем случае, что быстрее было отключить и повторно подключиться между каждым использованием mysqli_multi_query() чем использовать mysqli_next_result() .

Я хотел бы спросить, есть ли у кого-либо дополнительные знания из первых рук или контрольные доказательства, чтобы предложить приблизительное «обрезание» (на основе объема запроса или что-то еще), когда программист должен выбрать метод «новое соединение» по сравнению с методом «следующего результата».

Я также рад услышать любые проблемы, не связанные со скоростью. Использует ли Крейг функцию соединения какое-либо влияние на скорость?

Есть ли разница в скорости между высказыванием Крейга while:

 while ($mysqli->next_result()) {;} 

– против –

что я предлагаю:

 while(mysqli_more_results($mysqli) && mysqli_next_result($mysqli)); 

– против –

создавая новое соединение для каждого ожидаемого multi_query, перед запуском первого multi_query . Я только что протестировал это, и два mysqli_multi_query() s были без ошибок = no close() :

 $mysqli1=mysqli_connect("$host","$user","$pass","$db"); $mysqli2=mysqli_connect("$host","$user","$pass","$db"); 

– против –

Открытие и закрытие между каждой mysqli_multi_query() как Sebastien и Craig:

 $mysqli = newSQL(); $mysqli->multi_query($multiUpdates); $mysqli->close(); 

– против –

У кого-то есть еще один вариант тестирования?

Это не next_result() чтобы винить, а сами запросы. Время, затрачиваемое вашим кодом на выполнение, зависит от времени, которое требуется выполнить фактическим запросам.

Хотя mysqli_multi_query() возвращает управление довольно быстро, это не означает, что к этому времени все запросы были выполнены. Напротив, к моменту mysqli_multi_query() выполнен только первый запрос. Пока все остальные запросы поставлены в очередь на стороне mysql для асинхронного выполнения.

Из этого вы можете заключить, что next_result() не добавляет никакого тайм-аута самостоятельно – он просто ждет завершения следующего запроса. И если сам запрос требует времени, то next_result() должен ждать.

Зная, что вы уже можете сказать, какой способ выбрать: если вам не нужны результаты, вы можете просто закрыть соединение. Но на самом деле это будет просто подметать грязь под ковриком, оставляя все медленные запросы на месте. Таким образом, лучше держать next_result() на месте (особенно потому, что в любом случае вам нужно проверять наличие ошибок / затронутых строк и т. Д.), Но ускорить сами запросы.

Таким образом, оказывается, что для решения проблемы с next_result() вы должны фактически решить обычную проблему скорости запроса. Итак, вот несколько рекомендаций:

  1. Для выбранных запросов это обычный анализ индексирования / объяснения, уже объясненный в других ответах.
  2. Для запросов DML, особенно в партиях, существуют другие способы:

Говоря о случае Крейга, он очень похож на известную проблему скорости записи innodb. По умолчанию двигатель innodb настроен в очень осторожном режиме, когда не выполняется следующая запись, пока двигатель не обеспечит успешное завершение предыдущего. Таким образом, это делает записи ужасно медленными (что-то вроде только 10 запросов / сек). Общим обходным путем для этого является сделать все записи сразу. Для запросов вставки существует множество способов:

  • вы можете использовать несколько значений insert syntax
  • вы можете использовать запрос LOAD DATA INFILE
  • вы можете обернуть все запросы в транзакции.

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

  $multiSQL = "BEGIN;{$multiSQL}COMMIT;"; $mysqli->multi_query($multiSQL); while ($mysqli->next_result()) {/* check results here */} 

Если это не работает / неприменимо в вашем случае, я бы предложил изменить mysqli_multi_query() для одиночных запросов, запущенных в цикле, исследовать и оптимизировать скорость, а затем вернуться к multi_query.

Чтобы ответить на ваш вопрос:

смотреть, прежде чем прыгать

Я ожидаю, что ваш mysqli_more_results() (взгляд перед тем, как вы mysqli_more_results() ), не ускорит работу: если у вас есть n результатов, вы будете делать (2 * n) -1 вызовы в базу данных, тогда как Craig делает n + 1 ,

множественные соединения

multi_query выполняет async , поэтому вы просто добавляете накладные расходы на соединение.

открытие и закрытие db

Слушайте свой здравый смысл 😉 Но не теряйте следа, что вы делаете. Обертка запросов в транзакции сделает их атомарными . Это означает, что все они терпят неудачу , или все они преуспевают . Иногда это необходимо для того, чтобы база данных никогда не противоречила вашей вселенной дискурса. Но использование транзакций для ускорений может иметь нежелательные побочные эффекты. Рассмотрим случай, когда один из ваших запросов нарушает ограничение. Это приведет к сбою всей транзакции. Это означает, что если они не были логической транзакцией в первую очередь, и большинство запросов должно было преуспеть, вам нужно будет выяснить, что пошло не так, и что нужно будет переиздать. Стоимость вам больше, а не ускорение.

Запросы Себастьяна на самом деле выглядят так, как будто они должны быть частью более крупной транзакции, содержащей удаление или обновление родителей.

Вместо этого попытайтесь вспомнить

здесь нет ложки

В ваших примерах не было необходимости в нескольких запросах. Форма INSERT … VALUES принимает несколько кортежей для VALUES. Поэтому вместо того, чтобы готовить одно подготовленное заявление и завершать его повторные казни в транзакции, подобной вашему Общему смыслу . Вы можете подготовить одно заявление и выполнить его автоматически и автоматически. В соответствии с руководством mysqli это избавит вас от кучи раундов.

Итак, сделайте инструкцию SQL формы:

 INSERT INTO r (a, b, c) VALUES (?, ?, ?), (?, ?, ?), ... 

и связать и выполнить его. mysqldump –opt делает это, так почему бы и нет? Справочное руководство по mysql как раздел по оптимизации операторов . Посмотрите в разделе DML для запросов на вставку и обновление. Но понимание того, почему --opt делает то, что он делает, – хорошее начало.

заниженная стоимость подготовки заявления

Для меня реальная ценность подготовленных операторов заключается не в том, что вы можете выполнять их несколько раз, а в автоматическом входе. Для ничтожного единственного дополнительного клиент-серверного раунда вы избавляетесь от SQL-инъекции. SQL-инъекция является серьезной точкой внимания, особенно когда вы используете multi_query . multi_query сообщает mysql ожидать несколько запросов и выполнять их. Таким образом, вы не можете сбежать должным образом, и вам нужно развлечься:

Эксплуатация мамы

Поэтому моя лучшая практика:

  1. Мне действительно нужно несколько запросов?
  2. Если я это сделаю, сбегите от них или подготовьте их!