当隔离级别为READ-COMMITTED时,MySQL InnoDB是否在多个具有UNION的表上为SELECT创建一致的快照

当隔离级别为READ-COMMITTED时,MySQL InnoDB是否在多个具有UNION的表上为SELECT创建一致的快照,mysql,innodb,isolation-level,transaction-isolation,Mysql,Innodb,Isolation Level,Transaction Isolation,考虑如下两个表: TABLE: current ------------------- | id | dept | value | |----|------|-------| | 4| A | 20 | | 5| B | 15 | | 6| A | 25 | ------------------- TABLE: history ------------------- | id | dept | value | |----|------|--

考虑如下两个表:

TABLE: current
 -------------------
| id | dept | value |
|----|------|-------|
|   4|    A |    20 |
|   5|    B |    15 |
|   6|    A |    25 |
 -------------------

TABLE: history
 -------------------
| id | dept | value |
|----|------|-------|
|   1|    A |    10 |
|   2|    C |    10 |
|   3|    B |    20 |
 -------------------
+-----+--------+--------+------------+
| src | idx    | cnt    | SUM(value) |
+-----+--------+--------+------------+
| HST | 625874 | 625875 |  312569875 |
| CRT | 625875 |     10 |       8795 |
+-----+--------+--------+------------+
2 rows in set (1.43 sec)
这些只是简单的例子。。。在实际系统中,两个表都有相当多的列和行(当前为10k+行,历史为1M+行)

客户端应用程序连续(每秒数次)将新行插入当前表,并将旧的现有行从当前“移动”到历史(在单个事务中删除/插入)

在不阻塞此活动中的客户机的情况下,我们需要在两个表中获取每个部门的值的一致总和

将事务隔离级别设置为REPEATABLE READ后,我们只需执行以下操作:

SELECT dept, sum(value) FROM current GROUP BY dept;

SELECT dept, sum(value) FROM history GROUP BY dept;
并将两组结果相加。但每个查询都会阻止其各自表上的插入

将隔离级别更改为READ COMMITTED并执行相同的两个SQL可以避免阻塞插入,但现在如果在查询时从当前移动到历史,则存在重复计算条目的风险(因为每个选择都创建自己的快照)

那么问题来了。。。。如果执行联合,隔离级别读取提交会发生什么情况:

SELECT dept, sum(value) FROM current GROUP BY dept
UNION ALL
SELECT dept, sum(value) FROM history GROUP BY dept;

MySQL会同时生成两个表的一致快照(从而消除重复计算的风险)还是会先快照一个表,然后再快照第二个表?

我还没有找到任何结论性文档来回答我的问题,所以我开始尝试证明它。虽然不是科学意义上的证据,但我的发现表明,为联合查询中的所有表创建了一致的快照

这就是我所做的

创建表

DROP TABLE IF EXISTS `current`;

CREATE TABLE IF NOT EXISTS `current` (
  `id` BIGINT NOT NULL COMMENT 'Unique numerical ID.',
  `dept` BIGINT NOT NULL COMMENT 'Department',
  `value` BIGINT NOT NULL COMMENT 'Value',
  PRIMARY KEY (`id`));


DROP TABLE IF EXISTS `history`;

CREATE TABLE IF NOT EXISTS `history` (
  `id` BIGINT NOT NULL COMMENT 'Unique numerical ID.',
  `dept` BIGINT NOT NULL COMMENT 'Department',
  `value` BIGINT NOT NULL COMMENT 'Value',
  PRIMARY KEY (`id`));
创建一个过程,在当前表中设置10个条目(id=0,…9),然后在一个紧密循环中插入一个新行到当前,并将最旧的行从当前“移动”到历史。每次迭代都在一个事务中执行,因此当前表保持稳定的10行,而历史表则快速增长。在任何时间点,最小值(current.id)=最大值(history.id)+1

在同一数据库的另一个会话中,我们现在可以在我的原始帖子中尝试UNIONALL查询的变体

我将其修改为(a)减慢执行速度,(b)返回一个简单的结果集(两行),该结果集指示在查询运行时“移动”的任何条目是否丢失或重复计数

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

SELECT 'HST' AS src, MAX(id) AS idx, COUNT(*) AS cnt, SUM(value) FROM history WHERE dept IN (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
UNION ALL
SELECT 'CRT' AS src, MIN(id) AS idx, COUNT(*) AS cnt, SUM(value) FROM current WHERE dept IN (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
sum(value)
where dept in(…)
只是在那里为查询添加工作并降低查询速度

如果两个idx值相邻,则表示结果为阳性,如下所示:

TABLE: current
 -------------------
| id | dept | value |
|----|------|-------|
|   4|    A |    20 |
|   5|    B |    15 |
|   6|    A |    25 |
 -------------------

TABLE: history
 -------------------
| id | dept | value |
|----|------|-------|
|   1|    A |    10 |
|   2|    C |    10 |
|   3|    B |    20 |
 -------------------
+-----+--------+--------+------------+
| src | idx    | cnt    | SUM(value) |
+-----+--------+--------+------------+
| HST | 625874 | 625875 |  312569875 |
| CRT | 625875 |     10 |       8795 |
+-----+--------+--------+------------+
2 rows in set (1.43 sec)
我仍然很高兴听到关于这方面的任何权威信息