Как я могу сделать оператор обновления быстрее, который включает около 300 000 строк? - PullRequest
2 голосов
/ 03 апреля 2019

У меня есть приложение Laravel, которое выполняет обычную операцию, когда пользователь выбирает около 300 000 строк из таблицы базы данных, которая называется Sign с 3 столбцами. Столбцы таблицы описываются следующим образом: id(int-10), sign(varchar-16), status (int-10)

В таблице около 300 миллионов записей. Когда пользователь принимает некоторые записи, столбцы состояния этих строк изменяются на идентификатор пользователя. Обратите внимание, что пользователь всегда принимает около 300 000 записей одновременно.

Я увеличил innodb_buffer_pool_size и innodb_log_file_size до 2 ГБ и 1 ГБ соответственно. Система имеет 3,75 ГБ оперативной памяти.

Вот код-

$collection = Sign::select('sign')
                    ->where('status', 0)
                    ->where(DB::raw('CHAR_LENGTH(sign)'), '=', 7)
                    ->take(300000);

//write the the signs in $collection in a file here

$collection->update(['status' => $user->id]);

В моем случае данные таблицы извлекаются довольно легко в течение менее 1 с. Раньше на обновление требовалось около 100-200, но недавно я обновил свою операционную систему с Ubuntu 14 до 16, а после этого обновления - около 500-600. Есть ли способ сделать этот процесс быстрее? Стоит ли увеличивать ОЗУ?

Ответы [ 3 ]

0 голосов
/ 03 апреля 2019

Чтобы преодолеть медлительность CHAR_LENGTH(sign) без использования индекса, сгенерированные столбцы предоставляют решение.

Здесь мы создаем длину знака_счета, рассчитанную как длина знака в виде столбца:

ALTER TABLE sign ADD sign_length INT UNSIGNED AS (CHAR_LENGTH(sign))
, ADD INDEX status_sign_length(status,sign_length)

Затем используйте:

$collection = Sign::where('status', 0)
                ->where('sign_length', 7)
                ->update(['status' => $user->id])
                ->take(300000);

Примечание: larvel не мой сильный навык, исправления приветствуются.

0 голосов
/ 21 апреля 2019

2G для buffer_pool опасно высока для 3,75 ГБ ОЗУ Система подкачки? Если это так, либо уменьшите значение buffer_pool, либо увеличьте объем оперативной памяти. Подкачка ужасна для MySQL.

Поскольку новая ОС может потреблять больше ОЗУ для себя, приведенное выше утверждение может объяснить замедление.

Пожалуйста, укажите SQL, сгенерированный $collection->update(['status' => $user->id]);; не очевидно, что это будет. Насколько я знаю, $collection ведет список 300K идентификаторов всех строк и создает предложение IN для UPDATE.

UPDATEing строк намного дороже, чем SELECTing их. Первый должен хранить копию строк на случай сбоя, требующего ROLLBACK.

Какая версия MySQL? В оптимизаторе недавно произошли изменения для UPDATE.

Если между SELECT и UPDATE есть что-то, вам может понадобиться SELECT ... FOR UPDATE, иначе другое соединение может захватить те же строки и испортить данные!

0 голосов
/ 03 апреля 2019

Вместо выбора и обновления, вы просто должны нажать на запрос на обновление напрямую, как в laravel eloquent,

$collection = Sign::where('status', 0)
                ->whereRaw('CHAR_LENGTH(sign) = 7')
                ->update(['status' => $user->id]);

В любой операции выбора базы данных всегда будет быстро, потому что она просто включает сканирование таблицы, вы можетеполучить более подробную информацию, например, EXPLAIN SELECT * FROM sign;

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