¿Cuál es la forma más eficiente de realizar consultas de ACTUALIZACIÓN por lotes en MySQL?

10

Estoy escribiendo una aplicación que necesita eliminar una gran cantidad de actualizaciones de la base de datos durante un período prolongado de tiempo, y me he quedado atascado en cómo optimizar la consulta. Actualmente estoy usando INSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE, que funciona para agrupar todos los valores en una consulta, pero se ejecuta de manera insoportablemente lenta en tablas grandes. En realidad, nunca necesito insertar filas.

Otros enfoques que he visto son actualizar usando SET value = CASE WHEN...(lo cual sería difícil de generar debido a la forma en que estoy construyendo las consultas, y no estoy seguro sobre el rendimiento de CASEcientos / miles de claves), y simplemente concatenado múltiples actualizaciones ¿Alguno de estos sería más rápido que mi método actual?

Me desconcierta que, por lo que puedo ver, no hay una forma idiomática y eficiente de hacer esto en MySQL. Si realmente no hay una forma que sea más rápida ON DUPLICATE KEY, ¿valdría la pena cambiar a PostgreSQL y usar su UPDATE FROMsintaxis?

¡Cualquier otra sugerencia también es muy apreciada!

Editar: aquí hay una de las tablas que se actualiza con frecuencia. Eliminé los nombres de columna debido a que son irrelevantes.

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
fuente
Esto está en una máquina de prueba y no en producción, por lo que InnoDB no está completamente sintonizado correctamente. No estoy totalmente seguro de cómo funciona INSERT FROM, pero lo que dijiste parece correcto. Actualizó la pregunta con la información que solicitó.
jli

Respuestas:

14

Como está utilizando InnoDBtablas, la optimización más obvia sería agrupar múltiples UPDATEcorreos electrónicos en una transacción.

Al InnoDBser un motor transaccional, usted paga no solo por UPDATEsí mismo, sino también por todos los gastos generales transaccionales: administrar el búfer de transacciones, el registro de transacciones, vaciar el registro al disco.

Si está lógicamente cómodo con la idea, intente agrupar 100-1000 UPDATEs a la vez, cada vez envuelto así:

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

Posibles inconvenientes:

  • Un error colapsará toda la transacción (pero se solucionaría fácilmente en el código)
  • Es posible que espere mucho tiempo para acumular sus 1000 UPDATEs, por lo que también puede querer tener un tiempo de espera
  • Más complejidad en el código de su aplicación.
Shlomi Noach
fuente