日期:2014-05-16  浏览次数:20434 次

Oracle的并发和多版本控制

写不会阻塞读,这是Oracle和其他数据库的一个根本的区别。Oracle能够同时物化多个版本的数据,每次写入数据,都会另外生成一个版本,并附上时间戳,而当一个读操作发起时,它只能读到这个时间戳以内的版本,超过这个时间戳所更新的数据,是不会返回在结果集里面。所以一个程序如果只是读操作,那么它永远也不会被阻塞,也不会发生死锁。从某种意义上看,Oracle天然就具备了读写分离的特性。不像Mysql,需要采用主备集群的方式来实现读写分离。

?
?
支持的事务的隔离级别是Read Commited和Serializable。 对于Read Commit, 他允许“不可重复读”和“幻读”
  • 不可重复读
        • 第一次读获取了一个结果集, 然后集合中的某些列值发生了变化,那么同一session中再次读的时候,这些列值会被查出到结果集中
  • 幻读
      • 第一次读获取了一个结果集, 然后集合中的某些行被删除或者添加了新行,那么同一session中再次读的时候,这些行的改动被查出到结果集中
?
Serializable的实现和其他数据稍微有点不一样:
  • 首先由于读一致性的存在,读不会被阻塞,Serializable是对于更新操作而言的。当一个更新操作发现需要更新的数据是被锁定的时候,会抛出异常ORA_08177。而不是像其他数据库一样进行等待。
  • 一个事务开始后,期间不会有任何数据修改,直至Commit或者Rollback
?
Undo回滚段, 如果回滚段的空间小,那么用完后,就会发生snap shot too ?old错误 ORA_1555
?
?
查询热表的时候,IO操作会明显增多,原因在于热表的数据存在很多个数据更新的版本,当读到某个被更新的数据块, 发现时间戳太新, 于是去找到undo中的匹配的版本。如果仍然太新,那么就继续找下去。这些都是额外的IO操作,来获取undo信息.
?
?
而由于写一致性的存在,在更新热表的时候,如果发现某个数据的时间戳不一致,那么会重启更新。比如,修改了9999条数据,在准备修改10000的时候,发现其版本不对,那么数据库会重新更新这10000条。 而如果这个表上有相对于行修改的触发器,那么这些触发器会被重复地触发, 对性能的影响会非常恐怖。
?

?