Який найефективніший спосіб групувати 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;

Це на тестовій машині, а не на виробництві, тому InnoDB не повністю налаштований належним чином. Я не зовсім впевнений у тому, як працює INSERT FROM, але те, що ви сказали, здається правильним. Оновіть питання з інформацією, яку ви попросили.
jli

Відповіді:


14

Оскільки ви використовуєте InnoDBтаблиці, найбільш очевидною оптимізацією буде згрупування декількох UPDATEs в транзакції.

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

Якщо вам логічно подобається ця ідея, спробуйте згрупувати 100-1000 UPDATEсек за один раз, кожен раз завершуючи так:

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

Можливі мінуси:

  • Одна помилка зірве всю транзакцію (але її легко виправити в коді)
  • Ви можете довго чекати, щоб накопичити свої 1000 UPDATEс, тому ви також можете мати деякий час очікування
  • Більше складності в коді програми.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.