在 MySQL 中批处理 UPDATE 查询的最有效方法是什么?

jli*_*jli 13 mysql update

我正在编写一个应用程序,它需要在很长一段时间内刷新对数据库的大量更新,但我一直在研究如何优化查询。目前我正在使用INSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE,它可以将所有值批处理到一个查询中,但在大表上执行速度非常慢。我实际上不需要插入行。

我见过的其他方法是更新使用SET value = CASE WHEN...(由于我构建查询的方式,这将很难生成,而且我不确定CASE数百/数千个键的性能),并且只是多个连接更新。这些中的任何一个会比我目前的方法更快吗?

令我困惑的是,据我所知,在 MySQL 中没有惯用的、有效的方法来做到这一点。如果真的没有比 更快的方法,ON DUPLICATE KEY那么切换到 PostgreSQL 并使用其UPDATE FROM语法是否值得?

任何其他建议也非常感谢!

编辑:这是经常更新的表之一。我删除了列名,因为它们不相关。

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;
Run Code Online (Sandbox Code Playgroud)

Shl*_*ach 17

由于您使用的是InnoDB表,最明显的优化是将多个UPDATEs分组到一个事务中。

有了InnoDB,是一个交易引擎,你付出不只是为UPDATE自己,也为所有的事务开销:管理到交易缓存,事务日志刷新日志到磁盘。

如果您在逻辑上对这个想法感到满意,请尝试UPDATE一次将100-1000 s分组,每次都这样包装:

START TRANSACTION;
UPDATE ...
UPDATE ...
UPDATE ...
UPDATE ...
COMMIT;
Run Code Online (Sandbox Code Playgroud)

可能的缺点:

  • 一个错误将使整个交易崩溃(但很容易在代码中修复)
  • 您可能需要等待很长时间才能累积 1000UPDATE秒,因此您可能还需要一些超时时间
  • 应用程序代码更加复杂。