mysql oracle mvcc_MySQL MVCC 设计缺陷

虽然SQL-92规定了四种隔离级别,但是在引入MVCC后,RC/RR都是snapshot isolation下的变体。至于对隔离性和一致性的吐槽,引用沈洵的话:“快照读以更低的代价实现了更高的并发度,却不得不委身在原有事务框架内。其实ACID也只是一个标准,并非真理。”

既然是snapshot isolation,MySQL有什么问题呢,直接上案例:

准备工作:create table mvcc(x int auto_increment primary key,y int default 1);

insert into mvcc(y)  select 1 from mvcc; -- many times

Query OK, 2097152 rows affected (13.24 sec)

Records: 2097152  Duplicates: 0  Warnings: 0

RC/RR && autocommit = 0

TSession1Session2

T0select * from mvcc where y>1;

Empty set

T1update mvcc set y=3 where y>1;

T2updatingupdate mvcc set y=2

where x=3000000;

select * from mvcc where y>1;

+---------+------+

| x | y |

+---------+------+

| 3000000 | 2 |

+---------+------+

commit

Query OK, 0 rows affected

T3Query OK, 1 row affected (1.76 sec)

Rows matched: 1 Changed: 1

select * from mvcc where y>1;

+---------+------+

| x | y |

+---------+------+

| 3000000 | 3 |

+---------+------+

按照snapshot isolation来说session2的trx_id 大于session1的trx_id,从而session2的修改对session1应该是不可见的:即session1应该更新0行,但是MySQL在这里却对y=2进行了更新。

MySQL官方在5.5+的文档也针对该问题做出了Note:The snapshot of the database state applies to SELECT statements within a transaction, not necessarily to DMLstatements. If you insert or modify some rows and then commit that transaction, a DELETE or UPDATE statement issued from another concurrent REPEATABLE READ transaction could affect those just-committed rows, even though the session could not query them. If a transaction does update or delete rows committed by a different transaction, those changes do become visible to the current transaction.

根本原因在于MySQL在update/delete/insert/select for update/select lock in share mode时进行的是current read(select_lock_type != LOCK_NONE)而非consistent read。而Oracle解决这个问题的方式是对比current read和consistent read来决定是否进行query restart;对于该案例,session1在T2时更新到x=3000000时发现y发生了变化从而回滚了这个变更并进入query restart,最终结果就是在T3时更新了0行。

因此,如果业务依赖事务但是又不清楚具体数据库的实现细节,很容易就掉到坑里了;比如这个案例,就产生了"错误的"更新。

下面针对MySQL RR 给出一个非谓词更新的一个案例:如果不理解这块事务,在T3时想当然就会觉得结果应该是6000,可能就犯错了。

RR && autocommit=0

TSession1Session2

T1begin;

select * from t where x = 88;

+----+------+

| x | y |

+----+------+

| 88 | 3000 |

+----+------+

1 row in set (0.00 sec)

T2update t1 set b = 8000

where x = 88;

Query OK, 1 row affected

Rows matched: 1 Changed: 1

commit

T3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MVCC(多版本并发控制)是一种常见的数据库并发控制技术,它允许多个事务同时访问数据库,而不会互相干扰。下面是MySQL、PostgreSQL和OracleMVCC方式的对比: 1. MySQL MVCC方式: MySQL使用基于时间戳的MVCC方式。每个事务在开始时会分配一个唯一的时间戳,然后每个数据行都会存储一个创建时间和一个过期时间。当一个事务要读取一行数据时,MySQL会比较事务的时间戳和该数据行的创建和过期时间,如果该数据行的创建时间早于事务的时间戳,并且过期时间晚于事务的时间戳,则该数据行可见。 2. PostgreSQL MVCC方式: PostgreSQL使用基于快照MVCC方式。每个事务在开始时会创建一个快照,这个快照包含了数据库中所有数据的当前状态。每个数据行都会存储一个版本号和一个指向该版本的指针。当一个事务要读取一行数据时,PostgreSQL会比较事务的快照和该数据行的版本号,如果该数据行的版本号早于事务的快照,则该数据行不可见。 3. Oracle MVCC方式: Oracle使用基于undo的MVCC方式。每个事务在开始时会创建一个undo段,这个undo段用于存储所有被修改的数据的历史版本。每个数据行都会存储一个SCN(系统变更号),这个SCN表示该数据行的版本号。当一个事务要读取一行数据时,Oracle会比较事务的SCN和该数据行的SCN,如果该数据行的SCN早于事务的SCN,则该数据行可见。 总的来说,MySQLMVCC方式相对简单,但是在高并发情况下可能会出现性能问题。PostgreSQL的MVCC方式比较复杂,但是可以提供更好的并发性能。OracleMVCC方式则是一种比较成熟的实现,但是需要额外的存储空间来存储undo段。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值