ВЫБРАТЬ ДЛЯ ОБНОВЛЕНИЯ против ОБНОВЛЕНИЯ, затем ВЫБРАТЬ - PullRequest
6 голосов
/ 16 февраля 2011

Я создал приложение-службу, которое использует многопоточность для параллельной обработки данных, расположенных в таблице InnoDB (около 2-3 миллионов записей, и больше никаких запросов, связанных с InnoDB, выполняемых приложением).Каждый поток выполняет следующие запросы к упомянутой таблице:

  1. ЗАПУСК СДЕЛКИ
  2. ВЫБРАТЬ ДЛЯ ОБНОВЛЕНИЯ (ВЫБРАТЬ pk ИЗ таблицы, ГДЕ состояние = «новый» ПРЕДЕЛ 100 ДЛЯ ОБНОВЛЕНИЯ)
  3. ОБНОВЛЕНИЕ (ОБНОВЛЕНИЕ таблицы состояния SET = «заблокирован» ГДЕ ПК между X и Y)
  4. COMMIT
  5. УДАЛИТЬ (УДАЛИТЬ ИЗ таблицы, ГДЕ ПК между X и Y)

Ребята из forum.percona.com дали мне совет - не используйте SELECT FOR UPDATE и UPDATE из-за более длительного времени, необходимого для выполнения транзакции (2 запроса), и ожидаемых тайм-аутов блокировки.Их совет был (автокоммит включен):

  1. ОБНОВЛЕНИЕ (ОБНОВЛЕНИЕ таблицы SET, состояние = «заблокировано», поток = Z LIMIT 100)
  2. ВЫБРАТЬ (ВЫБРАТЬ pk ИЗ таблицы, ГДЕ поток =Z)
  3. УДАЛИТЬ (УДАЛИТЬ ИЗ ТАБЛИЦЫ ГДЕ pk МЕЖДУ X И Y)

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

Я много читал об оптимизации InnoDB и соответственно настроил сервер, так что мои настройки InnoDB на 99% в порядке.Этот факт также подтверждается тем, что первый сценарий работает нормально и лучше второго.Файл my.cnf:

innodb_buffer_pool_size = 512M
innodb_thread_concurrency = 16
innodb_thread_sleep_delay = 0
innodb_log_buffer_size = 4M
innodb_flush_log_at_trx_commit=2

Есть идеи, почему оптимизация не увенчалась успехом?

1 Ответ

2 голосов
/ 16 февраля 2011

Что я понимаю из описания вашего процесса:

  1. У вас есть таблица, в которой есть много строк, которые необходимо обработать.
  2. Вы выбираете строку из этой таблицы(используется для обновления), чтобы другие потоки не могли получить доступ к той же строке.
  3. Когда вы закончите, обновите строку и подтвердите транзакцию.
  4. И затем удалите строку из базы данных.

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

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

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

...