MySQL 的大型背景更新

Large background updates with MySQL

我正在构建一个由 MySQL 支持的 Web 服务,它会定期(例如,每天两次)缓存和索引来自外部来源的数据。更新例程是唯一修改缓存数据的东西;对于服务的其余部分,此数据是只读的。此外,通过对外部源的多个 HTTP 请求检索数据。请求的数量与检索到的数据量成正比。假设在组合时,数据不适合内存。我正在努力实现以下目标:

  1. 从服务的其余部分的角度来看,更新是原子的。该服务不应提供半更新数据。
  2. 新数据的批量插入要相当快。更新和插入不应使用单独的事务,而应在单个事务中使用 运行。最后应该有一个提交。
  3. 对于这些更新尽可能少地中断其余的服务。批量更新不应在更新发生时将其他会话锁定在访问旧数据之外。

我正在使用 InnoDB。

假设我有一个名为 webservice 的数据库,其中包含一个名为 data 的 table。更新数据的明显第一次尝试如下:

START TRANSACTION;
INSERT INTO `data`(`row1`, `row2`, `row3`) VALUES ('val1', 'val2', 'val3');
INSERT INTO `data`(`row1`, `row2`, `row3`) VALUES ('val4', 'val5', 'val6');
UPDATE `data` SET `row2` = 'val7' WHERE `id` = 3;
/* And so on for a very large number of INSERTs and UPDATEs. */
COMMIT;

据我所知,这满足了1和2,但违反了3。

我想到了另一个似乎满足 1、2 和 3 的解决方案。这在将插入新数据的另一个数据库中使用 "temp" tables,然后交换 tables.

START TRANSACTION;
DROP TABLE IF EXISTS `webservice_temp`.`data`;
CREATE TABLE `webservice_temp`.`data` LIKE `webservice`.`data`;
INSERT INTO `webservice_temp`.`data`
  SELECT * from `webservice`.`data`;
INSERT INTO `data`(`row1`, `row2`, `row3`) VALUES ('val1', 'val2', 'val3');
/* etc. */
COMMIT;
RENAME TABLE `webservice_temp`.`data` TO `webservice`.`data`;

这是解决我的问题的好方法吗?

如果您使用的是 InnoDB,则可以使用第一种方法(它将满足所有三个要求)START TRANSACTION WITH CONSISTENT SNAPSHOT。这允许在开始事务时从原始数据的快照为正在进行的读取请求提供服务。

WITH CONSISTENT SNAPSHOT 修饰符为支持它的存储引擎启动一致读取。 这仅适用于 InnoDB。

一致读取意味着 InnoDB 使用多版本控制向查询呈现数据库在某个时间点的快照。查询会看到在该时间点之前提交的事务所做的更改,而没有看到后来或未提交的事务所做的更改。

一种读取操作,使用快照信息基于时间点呈现查询结果,而不考虑其他事务同时执行的更改运行。如果查询到的数据已经被另一个事务更改,则根据undo log的内容重建原始数据。 http://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_consistent_read