Какой самый эффективный способ пакетных запросов UPDATE в MySQL?

10

Я пишу приложение, которое должно сбрасывать большое количество обновлений в базу данных в течение длительного периода времени, и я застрял в том, как оптимизировать запрос. В настоящее время я использую INSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE, который работает, чтобы объединить все значения в один запрос, но выполняется мучительно медленно на больших таблицах. Мне никогда не нужно вставлять строки.

Другие подходы, которые я видел, - это обновление с использованием SET value = CASE WHEN...(которое было бы трудно генерировать из-за способа, которым я строю запросы, и я не уверен в производительности CASEдля сотен / тысяч ключей), и просто несколько сцепленных обновления. Будет ли один из них быстрее, чем мой текущий метод?

Меня сбивает с толку, что, насколько я могу судить, в MySQL нет идиоматического и эффективного способа сделать это. Если нет более быстрого способа, ON DUPLICATE KEYстоит ли переходить на PostgreSQL и использовать его UPDATE FROMсинтаксис?

Любые другие предложения также приветствуются!

Изменить: вот одна из таблиц, которая часто обновляется. Я удалил имена столбцов, потому что они не имеют значения.

CREATE TABLE IF NOT EXISTS `table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `a` bigint(20) unsigned NOT NULL DEFAULT '0',
  `b` bigint(20) unsigned NOT NULL DEFAULT '0',
  `c` enum('0','1','2') NOT NULL DEFAULT '0',
  `d` char(32) NOT NULL,
  -- trimmed --
  PRIMARY KEY (`id`),
  KEY `a` (`a`),
  KEY `b` (`b`),
  KEY `c` (`c`),
  KEY `d` (`d`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
JLI
источник
Это на тестовой машине, а не на производстве, поэтому InnoDB не полностью настроен должным образом. Я не совсем уверен, как работает INSERT FROM, но то, что вы сказали, кажется правильным. Обновил вопрос с информацией, которую вы просили.
июля

Ответы:

14

Поскольку вы используете InnoDBтаблицы, наиболее очевидной оптимизацией будет группирование нескольких UPDATEэлементов в транзакцию.

С InnoDB, будучи транзакционный двигатель, вы платите не только за UPDATEсебя, но и для всех транзакционных накладных расходов: управление буфером транзакций, журнал транзакций, промывка журнала на диск.

Если вы логически согласны с этой идеей, попробуйте сгруппировать 100-1000 UPDATEс за раз, каждый раз оборачивая так:

START TRANSACTION;
UPDATE ...
UPDATE ...
UPDATE ...
UPDATE ...
COMMIT;

Возможные недостатки:

  • Одна ошибка разрушит всю транзакцию (но будет легко исправлена ​​в коде)
  • Вы можете долго ждать, чтобы накопить свои 1000 UPDATEс, поэтому вам также может потребоваться некоторое время ожидания.
  • Более сложный код вашего приложения.
Шломи Ноах
источник