Píšu aplikaci, která potřebuje vyprázdnit velké množství aktualizací databáze po delší dobu, a já jsem uvízl v tom, jak optimalizovat dotaz. V současné době používám INSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE
, který pracuje na dávkování všech hodnot do jednoho dotazu, ale na velkých tabulkách se provádí neuvěřitelně pomalu. Ve skutečnosti nikdy nemusím vkládat řádky.
Další přístupy, které jsem viděl, jsou aktualizace pomocí SET value = CASE WHEN...
(což by bylo obtížné vygenerovat kvůli způsobu, jakým vytvářím dotazy, a nejsem si jistý výkonem CASE
pro stovky/tisíce klíčů) a jednoduše vícenásobné zřetězené aktualizace. Bylo by jedno z nich rychlejší než moje současná metoda?
Znepokojuje mě, že pokud to dokážu, v MySQL neexistuje žádný idiomatický a účinný způsob. Pokud opravdu neexistuje způsob, který je rychlejší než ON DUPLICATE KEY
, stálo by to za to přejít na PostgreSQL a použít jeho UPDATE FROM
syntaxe?
Velmi vítáme i další návrhy!
Úpravy: Zde je jedna z tabulek, která se často aktualizuje. Odstranil jsem názvy sloupců, protože jsou irelevantní.
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;
Protože používáte tabulky InnoDB
, nejviditelnější optimalizací by bylo seskupení více UPDATE
s do transakce.
Když je InnoDB
, což je transakční motor, platíte nejen za samotný UPDATE
, ale také za všechny transakční režijní náklady: správa vyrovnávací paměti transakcí, protokolu transakcí, spláchnutí protokolu na disk.
Pokud jste s myšlenkou logicky spokojeni, zkuste seskupit 100–1 000 UPDATE
s najednou, vždy zalomené takto:
START TRANSACTION;
UPDATE ...
UPDATE ...
UPDATE ...
UPDATE ...
COMMIT;
Možné nevýhody:
UPDATE
s, takže můžete také chtít mít nějaký časový limit