一种会失败的常用数据仓库技术

来源:互联网 发布:网络时代的网络道德 编辑:程序博客网 时间:2024/06/10 14:40
书摘:TOM的“Oracle 9i10g编程艺术”
7.3.1 一种会失败的常用数据仓库技术
我看到,许多人都喜欢用这样一种常用的数据仓库技术:
(1) 他们使用一个触发器维护源表中的一个LAST_UPDATED 列,这与上一章的6.2.3 节中讨论的
方法很相似。
(2) 最初要填充数据仓库表时,他们要记住当前的时间,为此会选择源系统上的SYSDATE。例
如,假设现在刚好是上午9:00。
(3) 然后他们从事务系统中拉(pull)出所有行,这是一个完整的SELECT * FROM TABLE 查询,
可以得到最初填充的数据仓库。
(4) 要刷新这个数据仓库,他们要再次记住现在的时间。例如,假设已经过去了1 个小时,现
在源系统上的时间就是10:00.他们会记住这一点。然后拉出自上午9:00(也就是第一次拉出
数据之前的那个时刻)以来修改过的所有记录,并把这些修改合并到数据仓库中。
注意这种技术可能会在两次连续的刷新中将相同的记录“拉出”两次。由于时钟的粒度所致,这是不可
避免的。MERGE 操作不会受此影响(即更新数据仓库中现有的记录,或插入一个新记录)。
他们相信,现在数据仓库中有了自第一次执行拉出操作以来所修改的所有记录。他们确实可能有所
有记录,但是也有可能不是这样。对于其他采用锁定系统的数据库来说,这种技术确实能很好地工作,在
这些数据库中读会被写阻塞,反之写也会被读阻塞。但是在默认支持非阻塞读的系统中,这个逻辑是有问
题的。
要看这个例子有什么问题,只需假设上午9:00 至少有一个打开的未提交事务。例如,假设在上午
8:59:30 时,这个事务已经更新了表中我们想复制的一行。在上午9:00, 开始拉数据时,会读取这个表中
的数据,但是我们看不到对这一行做的修改;只能看到它的最后一个已提交的版本。如果在查询中到达这
一行时它已经锁定,我们就会绕过这个锁。如果在到达它之前事务已经提交,我们还是会绕过它读取查询
开始时的数据,因为读一致性只允许我们读取语句开始时数据库中已经提交的数据。在上午9:00 第一次
拉数据期间我们读不到这一行的新版本,在上午10:00 刷新期间也读不到这个修改过的行。为什么呢?上
午10:00 的刷新只会拉出自那天早上上午9:00 以后修改的记录,但是这个记录是在上午8:59:30 时修改的,
我们永远也拉不到这个已修改的记录。
在许多其他的数据库中,其中读会被写阻塞,可以完成已提交但不一致的读,那么这个刷新过程就能
很好地工作。如果上午9:00(第一次拉数据时)我们到达这一行,它已经上锁,我们就会阻塞,等待这一
行可用,然后读取已提交的版本。如果这一行未锁定,那么只需读取就行,因为它们都是已提交的。
那么,这是否意味着前面的逻辑就根本不能用呢?也不是,这只是说明我们需要用稍微不同的方式来
得到“现在”的时间。应该查询V$TRANSACTION,找出最早的当前时间是什么,以及这个视图中START_TIME
列记录的时间。我们需要拉出自最老事务开始时间(如果没有活动事务,则取当前的SYSDATE 值)以来经
过修改的所有记录:
select nvl( min(to_date(start_time,'mm/dd/rr hh24:mi:ss')),sysdate)
from v$transaction;
在这个例子中,这就是上午8:59:30,即修改这一行的事务开始的那个时间。我们在上午10:00 刷新
数据时,会拉出自那个时间以来发生的所有修改,把这些修改合并到数据仓库中,这就能得到需要的所有

东西。


有个疑问:假设8:59:30这个事务为T1,而V$TRANSACTION lists the active transactions in the system。

那么在上午10:00刷新数据时,如果T1事务已经提交了,那么V$TRANSACTION是查不到T1这个事务的。

0 0
原创粉丝点击