转载地址:

https://blogs.sap.com/2014/06/12/sap-hana-%E6%95%B0%E6%8D%AE%E5%BA%93%E5%B9%B6%E5%8F%91%E6%8E%A7%E5%88%B6/

 

SAP HANA 数据库并发控制

并发控制的责任

事务之间的相互影响可能导致数据库状态的不一致,即使各个事务能保持状态的正确性,而且也没有任何故障发生。如下图所示,当多个事务同事存取共享的数据库时,如何保证数据库的一致性?

/wp-content/uploads/2014/06/1_473396.png

由并发带来的不一致性包括:

(1)丢失数据修改

当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。

(2)读“脏”数据(脏读)

读“脏”数据是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被除撤消,而此时T1把已修改过的数据又恢复原值,T2读到的数据与数据库的数据不一致,则T2读到的数据就为“脏”数据,即不正确的数据。

( 3)不可重复读

指事务T1读取数据后,事务T2执行更新操作,使T1无法读取前一次结果。

(4)产生幽灵数据

按一定条件从数据库中读取了某些记录后,T2删除或插入了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录消失或增加。

串行调度

要解决这些问题,必须看一看保证并发执行的一组事务能保持数据库状态一致性的条件。如果每个事务都是首先一个事务的所有动作,然后是另一个事务的所有动作,以此类推,没有动作的混合,那么这一个调度就是串行调度。这样的调度是一致的,然而在实践中,这种调度无法达到多个事务的并发执行,SAP HANA如果按串行执行,也无法达到多核并行执行事务的目的。

可串行化调度

事务的正确性告诉我们,每个串行调度都能保持数据库的一致性。但是还有其他能保证一致性的调度吗?有,通常,不管数据库如果一个调度的结果与某一串行调度执行的结果等价,则称该调度是可串化调度,否则是不可串调度。实现可串行化调度,主要有封锁,时间戳,有效性确认等方法。

多版本的时间戳并发控制

我们给每个事务分配一个“时间戳”,记录最后读和写每个数据库元素的事务的时间戳,并比较这些值以保证按照事务的时间戳排序的串行调度,等价于事务的实际调度。为了使用时间戳来作为并发控制方式,调度器需要赋给每个事务T一个唯一的数值,即时间戳TS(T)。时间戳必须在事务首次通知调度器自己将开始时升序发出。在SAP HANA中,调度器根据事务的commit时间戳进行计数。

多版本的时间戳并发控制的一个重要方面是除了维护数据库当前的、存储在自身中的版本外,还维护数据库元素的旧版本。目的是允许其他情况下导致事务T中止(由于T的当前版本应在T以后写入)的读操作继续进行,这是通过让具有T时间戳的事务读适合它的X版本来达到的。如果数据库元素是块,或页,这种方法特别有用,因为这时所需要做的只是让缓冲区管理器在主存中容纳对当前摸个事务来说可能由于的某些块。由于SAP HANA是内存数据库,因此非常适合此种方法。此种方法也可以解决丢失数据修改、读”脏”数据(脏读)、不可重复读、产生幽灵数据这些一致性问题。

这种方式中数据的更新不是通过覆盖(Overwrite)已存在的记录,而是插入一个新版本的记录,这样在更新之前的事务可以用老版本的数据,不必担心之后的事务会修改它所用的数据。

如下图所示,五个事务先后执行,T1插入记录D,此时生成D的第一个版本V1。T1 commit之后,D的V1版本为当前版本。T3对D进行更新,产生D的第二个版本V2。T2为read事务,在开始时的时间戳在T1后T3 commit前,因此T2只能看到D的V1版本,并且在T2的整个生命周期中,不能看到D的其他版本。T4为read事务发生在T3commit只前,因此只能读取D的V1版本。T5发生在T3 commit之后,因此读取D的V2版本。在T3 commit之后,V2为D的当前版本,因此在T4结束之后,D的V1版本可以被移除掉了。

/wp-content/uploads/2014/06/2_473397.jpg

写锁及死锁

SAP HANA的基于时间戳的多版本并行调度可以确保并行读操作的一致性,但是他不能防止并行写操作导致的不一致(例如脏写,丢失更新)。为了防止在同一数据上进行并行写操作,SAP HANA使用独占式写锁。如果并行的事务想要进行写操作,必须首先获得该数据的锁。

此种方式可能发生死锁。如果两个事务T1和T2都需要更新两个记录R1和R2,然而R1的锁给了T1,R2的所给了T2那么T1无法更新R2,而且T2无法更新R1。此时,SAP HANA则会检查出死锁情况然后丢弃掉其中一个事务。利用实验进行验证,如下图,本人建立两个存储过程P1和P2,P1和P2都要更新一个表中的所有记录(10000条),P1更新方式为从最后一条记录往前更新,而P2更新方式为从第一条记录往后更新。两个存储过程基本同时运行,其中一个事务会被abort

3.PNG

4.PNG

写冲突

由于版本的隔离性,如果多个并行的事务都允许写同一条数据的新的版本,丢失数据修改有可能发生。如下图所示,T2先于T3开始,只能看到V1版本数据,当另一个并行事务T3进行读取后修改数据到V2版本并commit。由于版本的隔离性,T2无法看到新的版本V2,只能看到V1版本,如果T2被允许修改数据并且创建新版本V3,那么T3的修改版本V2将会丢失,从而导致更新丢失。因此SAP HANA不允许T2再次修改V1.

/wp-content/uploads/2014/06/5_473400.jpg

对该机制进行验证:

  1. 首先打开两个SQL命令窗口C1和C2,修改这两个窗口属性:Auto Commit和Isolation Level,如下图所示:

/wp-content/uploads/2014/06/6_473401.png

2. 然后在C1中执行

select NAME from “TEST”.“TEST1” WHERE ID = 1;

得到结果

/wp-content/uploads/2014/06/7_473402.png

3. 在C2中执行

select NAME from “TEST”.“TEST1” WHERE ID = 1;

update “TEST”.“TEST1” SET name = ‘C2’ WHERE ID = 1;

COMMIT;

4. 执行成功后,在C1中执行

select NAME from “TEST”.“TEST1” WHERE ID = 1;

update “TEST”.“TEST1” SET name = ‘C1’ WHERE ID = 1;

出现写冲突,系统不允许进行update操作,报如下错误:

/wp-content/uploads/2014/06/8_473403.png

 

posted on 2020-06-19 14:07  ricoo  阅读(941)  评论(0编辑  收藏  举报