J'écris une application qui doit éliminer un grand nombre de mises à jour de la base de données pendant une période prolongée, 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 en une seule requête, mais s'exécute de manière atroce sur les 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 CASE
pour des centaines/milliers de clés), et simplement de multiples mises à jour concaténées. 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 ON DUPLICATE KEY
, vaudrait-il la peine de passer à PostgreSQL et d'utiliser son UPDATE FROM
syntaxe?
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;
Puisque vous utilisez des tables InnoDB
, l'optimisation la plus évidente serait de regrouper plusieurs UPDATE
dans une transaction.
Avec InnoDB
, étant un moteur transactionnel, vous payez non seulement pour le UPDATE
lui-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 UPDATE
s à la fois, à chaque fois comme ceci:
START TRANSACTION;
UPDATE ...
UPDATE ...
UPDATE ...
UPDATE ...
COMMIT;
Inconvénients possibles:
UPDATE
s, donc vous pourriez aussi vouloir avoir un certain délai