计算机工程
COMPUTER ENGINEERING
1999年 第25卷 第12期 vol.25 No.12 1999



视图事务经历的串行化调度分析
焦　容　虞险云　严哲南　陈金海
1 串行化调度与数据一致性
　　实例化视图(Materialized View)是提高数据仓库查询效率的重要技术。相比虚拟视图(Virtual View)，它们都从数据仓库数据源派生出来，但在数据仓库中有实例化视图元组的物理存储，而虚拟视图的元组分布在一些相关的数据源中。实例化视图的元组物理存储可加速访问速度，同时也带来了数据源更新导致的视图数据不一致问题。在许多数据仓库应用中，比如银行业、零售业等行业由于数据量非常大，视图数据不一致现象大量存在，数据的一致性成了数据仓库视图维护的"生命线"。
　　视图数据不一致的一个很重要原因是多个数据源更新操作并发执行。如果能设法保证事务调度的可串行化特性，那么就能解决并发事务导致的数据不一致性问题。串行化调度的显著优点在于它的执行的原子性，调度中的每一事务操作都集中在一起，上一事务执行完后才开始下一事务，各事务之间互不干扰。正是由于串行事务各事务彼此保持相对独立，串行事务被取作数据一致性和正确性的标准。本文将就实例化视图经历的可串行化作一些探讨。
2 实例化视图的串行化调度理论
　　解决串行化调度问题，我们会首先想到传统的2PL协议。2PL协议适用条件很简单，要求一个事务内部的所有加锁操作应在所有撤锁操作之前发生。不幸得很，实例化视图维护与数据源的更新操作相互勾连后，2PL协议在解决实例化视图的串行化问题时遇到了困难。对2PL协议加以扩展，本文将提出一个新的实例化视图的串行化问题。在介绍该理论之前，先简要介绍一下串行化理论的基本知识。
2.1 串行化理论的基本知识
　　实例化视图的串行化理论会用到几个概念，有必要严格定义几个概念。
　　定义1：实例化视图经历可串行化并发事务经历可串行化当且仅当这些并发事务对实例化视图产生的影响与它们依次顺序执行产生的影响相同。
　　定义2：本地化谓词(Local Predicate)
　　我们知道，视图一般用SQL语句来定义，一句SQL语句实际上可看作一个谓词。那么所谓本地化谓词就是指该谓词(具体来说即该SQL语句)涉及的所有属性都来自同一个关系表。
　　定义3：本地化查询(Localized Query)
　　考虑由SQL语句查询定义的任意一个视图V，把该查询本地化以构建本地化查询视图V'。有两个步骤：
　　1)省略：省略SQL中的GROUPBY和HAVING子句，以及SELECT子句的集合属性，例如SUM()、AVG()等属性。
　　2)代替：构造最强条件C，C中只含两类谓词：本地谓词或只涉及SELECT子句中出现过的属性的谓词。用条件C代替原有WHERE子句中的条件。
　　定义4：派生集ds(Derivation Set)
　　对于前面提到的本地化查询视图V' ，V与V'之间存在共同属性。选择出V'里面的一些元组，这些元组在共同属性上的值与V的元组这些属性值相等。
　　举个例子来直观说明以上一些定义。
　　分析如下创建视图V的SQL语句：
　　CREATE VIEW AS
　　SELECT Stu.StuID,avg(Score) FROM Stu,Tutor,Subject 
　　　　WHERE Stu.StuID=Tutor.StuID and Tutor.StuID=Subject.
StuID
　　　　and Subject.Subname='Law'
　　GROUPBY Stu.StuID
　　HAVING avg(Score)>60
　　那么，根据本地化查询视图的构造规则，在构造强条件C时要删除WHERE子句中的条件Tutor.StuID=Subject.StuID，因为这个条件涉及两个关系表，非本地化谓词。最终构造结果如下： 
　　SELECT Stu.StuID FROM Stu,Tutor,Subject
　　　　WHERE Stu.StuID=Tutor.StuID and Subject.Subname='Law'
　　考虑视图V的元组t=(13315, 90),13315是学号属性Stu.StuID的值，该学生基本表中平均分属性avg(Score)值为90。派生集ds(t)是以下3个集合的并集：
　　.所有学号(StuID)为13315的Stu表中的元组集合
　　.所有导师情况表(Tutor)中的StuID(所带学生)属性为13315的元组集合
　　.所有科目表(Subject)科目为法学(Law)的元组集合。
　　这样派生集ds(t)就像是视图元组t的晴雨表。对ds(t)的任何修改都将影响到t，触发系统对t做相应的更新操作。
2.2 有效经历转化
　　先介绍将用到的几个记号。r,w表示对基本表的读和写，rV表示读实例化视图的元组，应指出rV可等价地解释成读虚拟视图(Virtual View)的元组，但虚拟视图中没有存储物理数据，读虚拟视图也即读出与虚拟视图对应的基本表关系中的有关元组。此外，用m[t]表示对视图元组t的维护操作，m[t]相当于宏操作，由读所有基本表，更新每个数据仓库视图这些操作组成。那么维护操作 m什么时刻被调用呢？设想在事务T中存在这样两个顺序操作，先对派生集ds(t)中的元组进行写操作，接下来读视图元组t。从上面对ds(t)的讨论可以知道，对ds(t)中的元组进行写操作实际上导致了视图元组 t的变化，因此必须在这两个顺序操作中插入维护操作m。具有这样特征的实例化视图事务经历称为有效经历。
　　可以想象，如果把对具备有效经历特征的实例化视图的读操作转译成对虚拟视图的读操作，有效经历的串行化问题就转化成虚拟视图经历的串行化问题。虚拟视图没有维护操作m[t]的概念，所以转译时应省略掉这些维护过程。
2.3 实例-串行化图的构造
　　定义5：实例化视图V的依赖图G(V)
　　G(V)是一个有向图。每个基本表关系和用于定义视图V的其他视图都对应一个结点。如果视图结点N2是从结点N1派生出的，那么有一条从N1指向N2的有向边。
　　定义6：虚拟视图的冲突操作
　　这里借鉴2PL串行化理论的冲突操作概念，如果虚拟视图两个操作中有一个写操作的话，就定义这是一对冲突操作。虚拟视图的冲突操作概念可用表1定义。
表1 虚拟视图冲突表

　r[u]rV[t]w[u]
r[u]NNY
rV[t]NNY
w[u]YYY


　　Y表示发生冲突操作，N表示无冲突操作。r[u]，w[u]表示对基本表元组t的操作，rV[t]表示对虚拟视图的元组t的读操作。当然u应是派生集ds(t)中的元素，u的写操作w[u]实际上引起了视图元组t的变化，所以在表1中w[u]和rV[t]是一对冲突操作。在虚拟视图冲突操作概念的基础上，下面提出实例-串行化图的构造规则。实例-串行化图的构造规则：
　　1)节点的构造：并发事务中的每个事务都对应一个节点。
　　2)边的构造：如果Ti中有一操作先于Tj中一操作发生，并且按照表1中的冲突概念，这两个操作是一对冲突操作，那么有一条从节点Ti指向节点Tj的有向边。
　　构造出实例-串行化图后，可依据下面的定理判断有效经历是否可串行化。
　　定理：一个有效经历是实例-可串行化的当且仅当实例-串行化图是无环的。
　　限于篇幅，不在本文给出该定理的证明。但必须强调定理的适用条件，定理仅适用于实例化视图经历是有效经历的情形。如果一个实例化视图经历是无效经历，这个实例化视图必定是不可串行化的，借助实例-串行化图的无环性判断无效经历的可串行化没有任何意义。
　　出现的符号做一些说明：
　　.rl[RX]：对关系表R中的元组X加读锁。
　　.r[RX]：读关系表R中的元组X。
　　.wl[RX]：对关系表R中的元组X加写锁。
　　.w[RX]：写关系表R中的元组X。
　　.u[RX]：对关系表R中的元组X解锁。
　　.VX：实例化视图V中的一个元组，这个元组由关系表R、S中的相关元组RX和SX作连接操作得出。
　　.VY：与VX相似，VY从关系表R、S中的相关元组RY和SY派生得出。
　　作为判断视图串行化定理的一个应用，表2描述了一个实例化视图串行化调度过程。不难看出，事务T1的解锁操作u[VY],u[RY],u[VY]都在所有加锁操作之后发生。同样，事务T2和T3的解锁操作也在加锁操作之后发生，因此并发事务T1、T2和T3满足2PL协议。但是通过下面的分析，我们发现该事务调度并非串行化调度。
表2 各时刻的事务执行情况

时标T1T2T3
1r[VY]　　
2　wl[SY]
3w[SY]
4wl[SY]
5提交
6　wl[RY]
7w[RY]
8u[RY]
9提交
10m[VY]　
11r[VY]
12r[VY]
13u[SY],u[RY],u[VY]
14提交


　　根据前面的视图有效经历概念，时刻t3的w操作、时刻t7的w操作与时刻t12的r操作之间插入了时刻t10的维护操作m[t]，表2描述的经历为有效经历。这样该有效事务经历就可以适用可串行化定理了。
　　时刻3出现的事务T2含读SY的操作w[SY]，后面时刻7事务T3包含写RY的操作w[RY]，按照实例-串行化图的构造规则，在图1中右半部出现了由T2指向T3的弧。再注意到在时刻1事务T1的r[VY]和稍后的时刻3就发生了T2的w[SY]操作构成了一对冲突操作，于是图1左半部中可看到T1指向T2的弧。在时刻7就发生了T3的w[RY]操作和时刻12事务T1的r构成了一对冲突操作，于是图1左半部中可看到T3指向T1的弧。实例-串行化图就包含一个环，从而该实例-串行化图是不可串行化的。

图1有环依赖图
　　综合对表2描述的实例化视图事务经历的讨论，可以知道实例-串行化图是一种有效的解决可串行化问题的策略。
2.4 串行化事务调度的实现
　　根据特定的需要，数据仓库的具体体系结构设计是相当灵活的。对广泛使用的数据仓库体系结构--斯坦福大学数据仓库研究课题组(WareHouse Information Project at Stanford, WHIPS)提出的WHIPS结构作一些结构引伸，我们提出一种改进的体系结构来支持视图可串行化特性，如图3所示。新结构图中增加了事务管理器这个新部件。事务管理器的主要功能是：集成器把收集到的一系列更新信息发送给事务管理器。把有关更新操作组合成具有原子性的多个事务后，视图管理器判断视图经历是否有效经历，如果是有效经历，进一步建立经历的依赖图，判断其无环性决定经历是否可串行化。确认事务经历可串行化后，把事务提交给数据仓库，执行事务的实例化视图更新过程，否则执行事务撤回操作。
　　如果采用图2的数据仓库体系结构判断出视图可串行化，可设计出事务调度的Seri-Sche算法。先介绍算法中将涉及的专用术语：

图2 数据仓库的新结构
　　(1)source_evaluate( )函数：计算查询Q的查询结果A。
　　1)MV(Materlized View)：实例化视图，有实在的元组存放在数据仓库中。
　　2)AL(Action Lists)：对数据仓库操作的动作列表。
　　3)pending(Q): 当调用source_evaluate( )过程处理查询Q时，同时发生了数据更新操作，该更新操作被暂时放进集合pending(Q)中。待查询Q处理完后，再对MV、AL作相应的处理。
　　4)UQS(Unanswered query set)：UQS为这样一类查询集，这类查询已发送至相关数据源，但数据仓库还没收到相应查询结果。
　　5)V< Ui >：更新Ui对视图V的影响。
　　接着描述Seri-Sche算法：
　　输入：更新操作Ui
　　输出：实例化视图MV的最新状态
　　伪代码： 
　　　对任一数据源x的处理：
　　1)数据源完成数据更新Ui后，把Ui发送至数据仓库。
　　2)一旦收到Qi查询，计算出当前数据源状态SS[x]下的查询结果Ai，并发送Ai至数据仓库。
　　对数据仓库部分的处理：
　　1)AL初始化为空集
　　2)收到更新Ui的信息后： 
　　3)if Ui是删除操作
　　　　begin
　　4)把来不及处理的查询Ui加到集合pending(Qj);
　　5)把key_delete(MV,Ui) 函数加到动作列表集合AL中
　　　　end
　　6)if Ui是插入操作 begin
　　7)令Qi＝V<Ui> 并且集合pending(Qi)保持原样
　　8)执行函数source_evaluate(Qi),且将结果赋值给Ai
　　9)对pending(Qi)中的每一个元素Uj, 执行键删除函数key_delete(Ai,Uj)
　　10)在AL集合中加入insert(MV,Ai)
　　　end
　　11)UQS为空集时，在MV上执行动作列表集合AL中所有元素，该执行操作为单事务操作。注意不要增加与MV中相同的元组。
　　12)动作列表集合AL置空
　　　End {of Seri-Sche算法}
3 总结及思考
　　本文通过举例的方式导出了数据仓库实例化视图的串行化理论，利用该理论来保证事务并发执行时的数据一致性。我们主要做的工作是在继承2PL协议的冲突操作概念的基础上，作出改进，提出实例-串行化图的构造规则，来判断数据仓库实例化视图的可串行性。一个可串行化实例化视图必须同时满足两个条件：首先该实例化视图经历是有效经历，这是可串行化的必要条件。第二个条件是实例-串行化图是无环的。
　　可是，数据仓库实例化视图的并发控制研究是一个很新的课题，值得研究的问题很多。举个例子，在对数据仓库频繁做增加、删除等更新操作，却相对较少地做读数据基本表操作情况下，也就是说数据仓库负载失衡时，本文提出的实例化视图的串行化理论还是不是最佳的并发控制方法呢？本文远远谈不上尽善尽美，如果能起到抛砖引玉的作用，我们的初衷就已获得满足。
作者单位：复旦大学计算机科学系，上海200433
参考文献
1 Yue Zhuge,Wiener J L,Molina H G.Multiple Consistency for DataWarehousing.http://db.stanford.edu.cn/zhuge/1996/mvc.ps
2 Bernstein P A,Hadzilacos V,Goodman N.Concurrency Control and Recovery in Database Systems.Addison-wesley,1987
