Qual è il modo più efficiente per eseguire il batch di query UPDATE in MySQL?


10

Sto scrivendo un'applicazione che deve scaricare un gran numero di aggiornamenti al database per un lungo periodo di tempo e mi sono bloccato su come ottimizzare la query. Attualmente sto usando INSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE, che funziona per raggruppare tutti i valori in una query, ma viene eseguito in modo lancinante lentamente su tabelle di grandi dimensioni. In realtà non ho mai bisogno di inserire righe.

Altri approcci che ho visto sono l'aggiornamento usando SET value = CASE WHEN...(che sarebbe difficile da generare a causa del modo in cui sto costruendo le query, e non sono sicuro delle prestazioni di CASEper centinaia / migliaia di chiavi), e semplicemente più concatenati aggiornamenti. Uno di questi sarebbe più veloce del mio metodo attuale?

Mi sorprende che, per quanto ne so, non esiste un modo idiomatico ed efficiente per farlo in MySQL. Se davvero non c'è un modo più veloce di ON DUPLICATE KEY, varrebbe la pena passare a PostgreSQL e usare la sua UPDATE FROMsintassi?

Anche altri suggerimenti sono molto apprezzati!

Modifica: ecco una delle tabelle che vengono aggiornate frequentemente. Ho rimosso i nomi delle colonne perché irrilevanti.

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;

Questo è su una macchina di prova e non sulla produzione, quindi InnoDB non è completamente ottimizzato correttamente. Non sono del tutto sicuro di come funzioni INSERT FROM, ma quello che hai detto sembra giusto. Aggiornata la domanda con le informazioni richieste.
jli

Risposte:


14

Dato che stai usando le InnoDBtabelle, l'ottimizzazione più ovvia sarebbe quella di raggruppare più UPDATEs in una transazione.

Con InnoDB, essendo un motore transazionale, non si paga solo per il UPDATEsé, ma anche per tutte le spese generali transazionale: la gestione del buffer di transazione, log delle transazioni, vampate di calore il registro su disco.

Se sei logicamente a tuo agio con l'idea, prova a raggruppare 100-1000 UPDATEs alla volta, ogni volta avvolti in questo modo:

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

Possibili aspetti negativi:

  • Un errore comprime l'intera transazione (ma sarebbe facilmente risolvibile nel codice)
  • Potresti aspettare molto tempo per accumulare 1000 UPDATEs, quindi potresti anche voler avere un po 'di timeout
  • Più complessità sul codice dell'applicazione.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.