Как сделать несколько вставок MySQL способом, который масштабируется (PHP) - PullRequest
2 голосов
/ 28 января 2010

В нашем PHP-коде есть цикл, который вставляет строки в таблицу. e.g.:

while ($info = mysql_fetch_assoc($someQuery)) {
    mysql_query("INSERT INTO X (i,j) VALUES ($info['ii'],$info['jj'])");
}

Это было хорошо несколько месяцев назад, потому что цикл повторялся бы только несколько раз. Однако из-за того, что наш сайт получает больше трафика, этот цикл теперь иногда повторяется 1000 и более раз. Таблица имеет некоторые издержки ( 4,305 КиБ ), и SELECT из этой таблицы появляются в MySQL slow-log , вероятно потому, что им приходится ждать длинный список вставок для снятия замков?

Как мне оптимизировать код, чтобы он лучше масштабировался?

Некоторые вещи, которые я решил попробовать:

  • INSERT DELAYED - Нужно разобраться в этом. Может ли это помочь?
  • Попробуйте вставить несколько строк в одном запросе. Но какой предел я должен установить? 50, 500, 1000?

Ответы [ 6 ]

7 голосов
/ 28 января 2010

Что такое $ someQuery ? Не могли бы вы использовать INSERT ... SELECT синтаксис?

4 голосов
/ 28 января 2010

Вы также можете создать такое утверждение:

INSERT INTO X (i,j)
VALUES ($info['ii'],$info['jj']),
(val, val),
...
(val, val);

Вы можете поэкспериментировать с различными ограничениями, чтобы определить, где, где угодно, ваш SQL становится слишком длинным. Тогда вы можете установить ограничение на что-то вменяемое.

4 голосов
/ 28 января 2010

Вместо повторения mysql_query() используйте подготовленные операторы . Это гораздо более эффективный способ многократного повторения одного и того же запроса с разными значениями.

Кроме того, я бы посмотрел на те запросы, которые появляются в медленном журнале. Используйте EXPLAIN (<query>), чтобы проверить, используются ли индексы.

2 голосов
/ 28 января 2010

Один из самых быстрых способов получить данные в MySQL - это LOAD DATA INFILE. Думайте об этом как о импорте CSV. Вы можете записывать данные по одной строке за раз на диск, а затем выполнять массовую загрузку. Согласно эта страница на скоростях вставки LOAD DATA INFILE в 20 раз быстрее прямой INSERT.

Однако возможны и другие нежелательные побочные эффекты, поскольку таблица может быть заблокирована для всего процесса, а не только для одной строки за раз. Запуск этого, например, Пакеты из 100 строк могут сделать обе части проблемы управляемыми - думаю, вам просто нужно поэкспериментировать.

2 голосов
/ 28 января 2010

Важно то, что сказал Бен Джеймс. Подготовленные операторы работают намного быстрее, если вы выполняете тот же SQL и просто меняете в нем параметры.

Кроме того, вы можете изменить весь цикл на что-то вроде:

INSERT INTO x (i, j) SELECT (here goes your $someQuery)

Конечно, вы должны адаптировать $ someQuery, поэтому я выбираю только два столбца одного типа (или может быть приведен автоматически) как столбцы i и j.

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

1 голос
/ 29 января 2010

В новых версиях MySQL есть хранимые процедуры и функции. Вы можете использовать структурированный язык с переменными, циклами и условными блоками. Одна хранимая процедура должна быть быстрее, чем многие независимые вставки. Тем не менее, это новый язык для изучения.

Для использования хранимых процедур вам нужно расширение mysqli в php.

Вы также можете посмотреть на mysqli_multi_query.
http://pl.php.net/manual/en/mysqli.multi-query.php

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