Quelle est la manière la plus efficace de grouper des requêtes UPDATE dans MySQL?

10

J'écris une application qui doit éliminer un grand nombre de mises à jour de la base de données pendant une longue période, et je suis resté coincé sur la façon d'optimiser la requête. Actuellement, j'utilise INSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE, qui fonctionne pour regrouper toutes les valeurs dans une seule requête, mais s'exécute de manière atroce lentement sur de grandes tables. Je n'ai jamais vraiment besoin d'insérer de lignes.

D'autres approches que j'ai vues consistent à mettre à jour à l'aide de SET value = CASE WHEN...(qui serait difficile à générer en raison de la façon dont je construis les requêtes, et je ne suis pas sûr des performances de CASEpour des centaines / milliers de clés), et simplement à plusieurs concaténations mises à jour. L'un ou l'autre serait-il plus rapide que ma méthode actuelle?

Cela me déconcerte que, pour autant que je sache, il n'y a pas de moyen idiomatique et efficace de le faire dans MySQL. S'il n'y a vraiment pas de moyen plus rapide que cela ON DUPLICATE KEY, cela vaudrait-il la peine de passer à PostgreSQL et d'utiliser sa UPDATE FROMsyntaxe?

Toutes autres suggestions sont également grandement appréciées!

Edit: voici l'un des tableaux qui est mis à jour fréquemment. J'ai supprimé les noms de colonnes car ils n'étaient pas pertinents.

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
la source
C'est sur une machine de test et non sur la production, donc InnoDB n'est pas complètement réglé correctement. Je ne suis pas totalement sûr du fonctionnement de INSERT FROM, mais ce que vous avez dit semble juste. Mise à jour de la question avec les informations que vous avez demandées.
jli

Réponses:

14

Puisque vous utilisez des InnoDBtables, l'optimisation la plus évidente serait de regrouper plusieurs UPDATEs dans une transaction.

Avec InnoDB, étant un moteur transactionnel, vous payez non seulement pour UPDATElui - même, mais aussi pour tous les frais généraux transactionnels: gestion du tampon de transaction, journal des transactions, vidage du journal sur le disque.

Si vous êtes logiquement à l'aise avec l'idée, essayez de regrouper 100-1000 UPDATEs à la fois, chaque fois emballé comme ceci:

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

Inconvénients possibles:

  • Une erreur réduira la transaction entière (mais serait facilement corrigée dans le code)
  • Vous pouvez attendre longtemps pour accumuler vos 1000 UPDATEs, vous pouvez donc également souhaiter
  • Plus de complexité sur votre code d'application.
Shlomi Noach
la source