Friday, January 18, 2008

转:把握数据仓库的键

数据仓库 ONETruth
数据仓库就是面向主题的、集成的、稳定的、不同时间的数据集合,用以支持经营管理中的决策制定过程。目的是解决在信息技术(IT) 发展中存在的拥有大量数据、然而有用信息贫乏(Data rich-Information poor)的问题。
数据仓库的特点
面向主题
集成性—企业数据框架
历史性、稳定性
管理决策支持


foreign key:

part of it must be the PK of the referenced table (i.e. it must exist there)

在《数据仓库》(Inmon)一书中,主要描述了以下3种incremental extract方法:

1.数据增量抽取,主要是基于时间戳的

2、扫描增量文件,实际上就是关系数据库的归档日志。

3、前后映像对比

by1:
首先需要定义一张数据字典表,定义需要进行处理的任务,其中主要包括业务数据库和目标数据库的表名、字段列表、以及where条件,flag of succeed/failure等;
1、获取数据仓库目标表目前的最大时间(读取字典表或者当前表均可)

2、获取业务数据库业务表目前的最大时间(需要到业务系统中去读取)

3、如果业务数据库业务表数据为空,退出执行

4、如果数据仓库为空,业务数据库不为空,则再次读取业务数据库最小时时间

5、如果均不为空,则设置开始抽取最小时间和最大时间

6、最大时间设置为整点

7、根据控制事务处理大小的粒度,进行循环抽取

8、拼写SQL语句,写成类似以下的形式

INSERT INTO TargetTable (TargetFieldList)

SELECT SourceFieldList FROM SourceTable

WHERE WhereFieldName> BeginDate

AND WhereFieldName< BeginDate+粒度

9、处理状态写入该字典表

根据笔者多年的数据仓库实施经验,同时结合ETL的过程原理和数据仓库建设方法归纳总结了以下优化的方案,详细内容请读者参考下文:这篇论坛文章(赛迪网技术社区)

  1.引言

  数据仓库建设中的ETL(Extract, Transform, Load)是数据抽取、转换和装载到模型的过程,整个过程基本是通过控制用SQL语句编写的存储过程和函数的方式来实现对数据的直接操作,SQL语句的效率将直接影响到数据仓库后台的性能。

  目前,国内的大中型企业基本都具有四年以上计算机信息系统应用经验,积累了大量可分析的业务数据,这些信息系统中的数据需要通过搭建数据仓库平台才能得到科学的分析,这也是近几年数据仓库系统建设成为IT领域热门话题的原因。

  2.优化的思路分析

  数据仓库ETL过程的主要特点是:面对海量的数据进行抽取;分时段对大批量数据进行删除、更新和插入操作;面对异常的数据进行规则化的清洗;大量的分析模型重算工作;有特定的过程处理时间规律性,一般整个ETL过程需要在每天的零点开始到6点之前完成。所以,针对ETL过程的优化主要是结合数据仓库自身的特点,抓住需要优化的主要方面,针对不同的情况从如何采用高效的SQL入手来进行。

  优化的实例分析

  目前数据仓库建设中的后台数据库大部分采用Oracle,以下的SQL采用Oracle的语法来说明,所有的测试在Oracle9i环境中通过,但其优化的方法和原理同样适合除Oracle之外的其他数据库。

  3.1索引的正确使用

  在海量数据表中,基本每个表都有一个或多个的索引来保证高效的查询,在ETL过程中的索引需要遵循以下使用原则:

  (1) 当插入的数据为数据表中的记录数量10%以上时, 首先需要删除该表的索引来提高数据的插入效率,当数据全部插入后再建立索引。

  (2) 避免在索引列上使用函数或计算,在WHERE子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描。举例:

  低效: SELECT * ROM DEPT WHERE SAL * 12 > 25000;

  高效: SELECT * FROM DEPT WHERE SAL > 25000/12;

  (3) 避免在索引列上使用NOT和”!=” , 索引只能告诉什么存在于表中,而不能告诉什么不存在于表中,当数据库遇到NOT和”!=”时,就会停止使用索引转而执行全表扫描。

  (4) 索引列上用>=替代>

  高效: SELECT * FROM EMP WHERE DEPTNO >=4

  低效: SELECT * FROM EMP WHERE DEPTNO >3

  两者的区别在于,前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录。

  (5) 函数的列启用索引方法,如果一定要对使用函数的列启用索引,Oracle9i以上版本新的功能:基于函数的索引(Function-Based Index)是一个较好的方案,但该类型索引的缺点是只能针对某个函数来建立和使用该函数。

  CREATE INDEX EMP_I ON EMP (UPPER( ENAME));       

  SELECT * FROM EMP WHERE UPPER(ENAME) = ‘BLACKSNAIL’;

  3.2 游标的正确使用

  当在海量数据表中进行数据的删除、更新和插入操作时,用游标处理的效率是最慢的方式,但它在ETL过程中的使用又必不可少,而且使用有着及其重要的地位,所以游标的正确使用尤为重要。

  对数据仓库维表的数据进行维护时,因为需要保证维表ID的一致性,所以采用游标的是数据维护完整性的最好方式。由于它的效率低,如果按照普通的方式将无法处理大数据量的维表数据维护(一般是指10万条记录以上的维表),以下是处理这种情况的有效方式:

  (1) 在数据抽取的源表中使用时间戳,这样每天的维表数据维护只针对更新日期为最新时间的数据来进行,大大减少需要维护的数据记录数。

  (2) 在INSERT和UPDATE维表时都加上一个条件来过滤维表中已经存在的记录,实例为:

  INSERT INTO DIM_CUSTOMER SELECT * FROM ODS_CUSTOMER WHERE ODS_CUSTOMER.CODE NOT EXISTS (DIM_CUSTOMER.CODE)

  (3) 使用显式的游标(CURSORs) ,因为使用隐式的游标将会执行两次操作,第一次检索记录,第二次检查TOO MANY ROWS 这个EXCEPTION,而显式游标不执行第二次操作。

  3.3数据抽取和上载时的SQL优化

  ◆3.3.1 WHERE子句中的连接顺序

  ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其它WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。

  低效:SELECT * FROM EMP E WHERE SAL > 50000 AND JOB = ‘MANAGER’ AND 25 <(SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO);

  高效:SELECT * FROM EMP E WHERE 25 <(SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO) AND SAL > 50000 AND JOB = ‘MANAGER’;

  ◆3.3.2 删除全表时用TRUNCATE替代DELETE

  当DELETE删除表中的记录时,有回滚段(rollback segments ) 用来存放可以被恢复的信息,而当运用TRUNCATE时,回滚段不再存放任何可被恢复的信息,所以执行时间也会很短。同时需要注意TRUNCATE只在删除全表时适用,因为TRUNCATE是DDL而不是DML。

  ◆3.3.3 尽量多使用COMMIT

  ETL中同一个过程的数据操作步骤很多,数据仓库采用的是数据抽取后分析模型重算的原理,所以对数据的COMMIT不像业务系统为保证数据的完整和一致性而需要某个操作过程全部完成才能进行,只要有可能就在程序中对每个DELETE、INSERT和UPDATE操作尽量多使用COMMIT, 这样系统性能会因为COMMIT所释放的资源而大大提高。

  ◆3.3.4 用EXISTS替代IN

  在许多基于基础表的查询中,为了满足一个条件往往需要对另一个表进行联接,例如在ETL过程写数据到模型时经常需要关联10个左右的维表,在这种情况下,使用EXISTS而不用IN将提高查询的效率。

  ◆3.3.5 用NOT EXISTS替代NOT IN

  子查询中,NOT IN子句将执行一个内部的排序和合并,无论在哪种情况下,NOT IN都是最低效的,因为它对子查询中的表执行了一个全表遍历。用NOT EXISTS替代NOT IN将提高查询的效率。

  ◆3.3.6 优化GROUP BY

  提高GROUP BY 语句的效率,可以通过将不需要的记录在GROUP BY 之前过滤掉。

  低效: SELECT JOB , AVG(SAL) FROM EMP GROUP BY JOB HAVING JOB = ‘PRESIDENT’ OR JOB = ‘MANAGER’

  高效: SELECT JOB , AVG(SAL) FROM EMP WHERE JOB = ‘PRESIDENT’ OR JOB = ‘MANAGER’ GROUP BY JOB

  ◆3.3.7 有条件的使用UNION-ALL 替换UNION

  ETL过程针对多表连接操作的情况很多,有条件的使用UNION-ALL 替换UNION的前提是:所连接的各个表中无主关键字相同的记录,因为UNION ALL 将重复输出两个结果集合中相同记录。

  当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并,然后在输出最终结果前进行排序。如果用UNION ALL替代UNION,这样排序就不是必要了,效率就会因此得到提高3-5倍

  ◆ 3.3.8 分离表和索引

  总是将你的表和索引建立在不同的表空间内,决不要将不属于ORACLE内部系统的对象存放到SYSTEM表空间里。同时确保数据表空间和索引表空间置与不同的硬盘控制卡控制的硬盘上

4、有一点要主要的是,在SQLServer中有两种使用链接数据库的方法:

OPENQUERY ( linked_server , 'query' )

linked_server_name.catalog.schema.object_name的四部分名称

这两种方法各有利弊,第二种容易阅读一些;第一种方法据说把语句提交到源数据库执行的,效率可能会高些(实际的资料并未找到)。

其次这两种方法在使用起来语法有点差别,第一种方法采用的是宿主数据库的语法形式,第二种方法采用的是SQLServer本身的语法形式。因此在写脚本的时候也会有所不同。主要差别是在字段列表和条件处,暂时采用第一种方

本文主要是针对关于数据增量抽取的模拟实现——原理进行实现的

实现的环境:

业务数据库:Oracle9i

数据仓库数据库:SQLServer2000


)^a5sS)KFu/UJO~420351、前提SQLServer服务器已经安装Oracle驱动,不再详细累述ITPUB个人空间9n{ s*Z/r5wd
2、创建链接数据库
%~q_P`42035打开企业管理器->安全性-链接服务器-右键新建
(C#~|"S.Av42035
7y)t9nr|#rou5JBH42035通常情况当链接数据库创建好,进行打开的时候都会弹出一下错误窗口:ITPUB个人空间:q0@?5BtURJ

%LN-Q Mg dK C42035一般情况下运行C:Program FilesCommon FilesSystemOle DBmtxoci81_win2k.reg该文件后,重启SQLServer数据库,再重新连接;
'| eTkq cO42035如果仍有问题,重启操作系统,即可OK。
4m,]L e:Z"BFTP420353、创建Oracle环境脚本ITPUB个人空间T(`&X3Rf i~i _t
--创建Oracle业务系统表结构

CREATE TABLE SourceTable
\MR#{ ^'Al3W-n42035(ITPUB个人空间2O T,kRfM dG0h
ID1 VARCHAR2(50),ITPUB个人空间 q5A fw*{8k
ID2 VARCHAR2(50),
L r%|L\ c&[1V0x42035Measure1 INTEGER,ITPUB个人空间'N i@2}K"N
Measure2 INTEGER,
!\`;O _M8w'F&co42035CloseDate DATE
:y M g lf%P42035)

--创建测试数据

DECLARE

-- Local variables here
gt,cHO7rky5h$C7Cd42035i INTEGER;

BEGIN

-- Test statements here

FOR i IN 1..365 LOOP

INSERT INTO SourceTableITPUB个人空间.DtK'q a[9x ][[&|
VALUES(i,i,i,i,TO_DATE('2006-01-01','yyyy-mm-dd')+i);ITPUB个人空间6R&T8Oov9|3T_3A
INSERT INTO SourceTable
s{!b8as'h;L42035VALUES(i,i,i,i,TO_DATE('2006-01-01 12:00:00','yyyy-mm-dd hh24:mi:ss')+i);

ENDLOOPITPUB个人空间?#B2aJs.F$FDJ$o
COMMIT;

END;

ITPUB个人空间 FWJuQK(F?
4、创建SQLServer数据仓库环境脚本
z[As.?BG42035--创建系统参数表内

CREATE TABLE ExtractTaskList (ITPUB个人空间Vxmr%LAsU
TaskName VARCHAR(32) ,ITPUB个人空间 hAI&^7UM
TargetTable VARCHAR(32) ,ITPUB个人空间b!~(P#aU x `Q1p,O
TargetFieldList VARCHAR(500) ,ITPUB个人空间j(jrLykq)K-DV
SourceTable VARCHAR(32) ,ITPUB个人空间RH$T0q:c7\.o Xq
SourceFieldList VARCHAR(500) ,
%At Ob]42035WhereFieldName VARCHAR(32) ,ITPUB个人空间_Kq`U/w*dlTE!e
IncType INT,ITPUB个人空间:ex6`3t PJ%P-D
TransType INT,ITPUB个人空间aYA_'AFk|b
TargetDate DATETIME,ITPUB个人空间j.k`K@;`KcY6y
SourceDate DATETIME,ITPUB个人空间hY4s:cz4N
Flag INT,
:in*|E?:X7u42035Note VARCHAR (500)
K$y:uC#k42035)

GO

--创建数据仓库目标表

CREATE TABLE TargetTable (
3v+X3PD}42035ID1 VARCHAR(50),
P7Z'A+H^5x(y9H42035ID2 VARCHAR(50),
3Xg+x|]oV XEH42035Measure1 DECIMAL(18, 0),ITPUB个人空间*?b?v(]2A5|
Measure2 DECIMAL(18, 0),
x v:I/~(U42035CloseDate DATETIMEITPUB个人空间4K(a?a3L,Dg0H6k:Xq0MB
)

GO

ITPUB个人空间)t)I+AD[/n
5、创建SQLServer数据仓库ETL脚本ITPUB个人空间 h4i6j"[4c I u |\
脚本考虑到现实的问题,已经做了许多取舍,不再追求全部动态实现,旨在给定一个模板,在有限的范围内可以更改每次抽取的周期,每次时间的跨度,抽取的字段,表等等;数据字典表仅仅利用了其中的四个字段:任务名称,当前抽取时间、结束时间、抽取状态。CREATE PROCEDURE p_org_Extract
)pA^wvw E'z42035ASITPUB个人空间/ON-FnRm0S#x
DECLARE @sql VARCHAR(3000)

BEGIN

DECLARE @BeginDateDATETIME,ITPUB个人空间7J {'c$W9y5U.g
@EndDateDATETIME,ITPUB个人空间#j5Y7@DJA0|
@TaskNameVARCHAR(32),
k8}fS4~-V9L9D42035@FlagINTEGER,ITPUB个人空间z{*P!{&Pz)~ r
@NumINTEGER,
zV/qX(V!wRHQ42035@CurrDateDATETIME

SELECT @Num = COUNT(TaskName) FROM ExtractTaskList
&ui'fEo@42035WHERE UPPER(TaskName) = UPPER('test')

IF @Num != 1
8u;spI^ E42035INSERT INTO ExtractTaskList(TaskName,IncType,TransType) VALUES('test',2,2)

--获取列表中的当前任务的时间戳和状态ITPUB个人空间P3C3}"z"W)u)E%X L
SELECT @BeginDate = SourceDate,@Flag = Flag FROM ExtractTaskList WHERE TaskName='TEST'

--如果上次执行未成功,这样取值效率会高一些,则从数据仓库表中直接读取ITPUB个人空间.E4P P] lz[d2ns \
--TargetDate和SourceDate可能会不一致ITPUB个人空间&Ck ?1hsT:i,Z
IF @Flag = 2 OR @Flag IS NULL
zK.y C k0N!`&{42035SELECT @BeginDate = DATEADD(ss,1,MAX(closedate)) FROM TargetTable

--如果数据仓库无数据,则从业务系统中直接读取,也可以设置一个默认的初始化时间
'ia j&Vv7E4A{4q42035IF @BeginDate IS NULLITPUB个人空间FJ'V%\b2i0Kb%U
SELECT @BeginDate = MinLogDate FROM OPENQUERY(SOURCE,'SELECT MIN(CloseDate) AS MinLogDate FROM SourceTable')

--如果仍无数据,则表示无数据可抽取,退出执行
i$Q)po{Z o42035IF @BeginDate IS NULL
Q#[4\.L*bT9t |X42035RETURNITPUB个人空间xi T*WFK

)K@W%}(r^42035--抽取结束时间为当前时间前一天,每次循环抽取1天数据,可以更改dd为hh,变成按小时抽取ITPUB个人空间{5W(UQ/p ]
--通常业务系统是连续的,如果有疑问也可以从业务系统中获取最大时间ITPUB个人空间 x_X9R&Di(i.b
SELECT @EndDate = CONVERT(DATETIME,LEFT(CONVERT(VARCHAR,GETDATE(),120),10)+' 00:00:00')

--更新当前开始时间和结束时间
,If&E9O+Uz.V$B G7x42035UPDATE ExtractTaskListITPUB个人空间)QA:x)tb7s ~y'[
SET TargetDate = @BeginDate,
0y7r*p;D e:Gdy8aRx+p)?42035SourceDate = @EndDateITPUB个人空间#E)^3\9] V"v/k(_M
WHERE UPPER(TaskName) = UPPER('test')
(sX I d La42035
1\v7y;Z?A"Q"DB o42035WHILE @BeginDate < @EndDateITPUB个人空间:Mi~9}.f |-x.V:Nc
BEGIN
${2AB*RGgT42035SELECT @sql = ' INSERT INTO TargetTable
s*xu4K aC42035(
H~!g"q`$~&m#tB42035ID1,
(Bub7B"_/\4u42035ID2,ITPUB个人空间 u.X_A'Bq:r][
Measure1,
1s[u*o;k42035Measure2,
imd)GP1E7l!TJ42035CloseDateITPUB个人空间N^2q%ymoP%U
)SELECT * FROM OPENQUERY(SOURCE,''select
Ry'^$Vj%~ fc42035ID1,
8V_G*O/j h-m42035ID2,
yW9e(]S[42035Measure1,ITPUB个人空间(b~|q;an1Yv}
Measure2,ITPUB个人空间 t.U X{#lc
CloseDate
C)Ss`0[%q \&]'t Jh42035FROM SourceTableITPUB个人空间Kdh?lO]
WHERE CloseDate >= TO_DATE(''''' + CONVERT(varchar,@BeginDate,120) + ''''', ''''YYYY-MM-DD HH24:MI:SS'
0\o$xt-S w^n:L42035+ ''''') AND CloseDate < TO_DATE(''''' + CONVERT(varchar,DATEADD(day,1,@BeginDate),120) + ''''', ''''yyyy-mm-dd HH24:MI:SS'
]g J/~F2PP42035+ ''''') AND CloseDate < TO_DATE(''''' + CONVERT(varchar,@EndDate,120) + ''''', ''''YYYY-MM-DD HH24:MI:SS'ITPUB个人空间y(uto$_3]!vV2K
+ ''''')'')'
2\ K&y"]kr42035--PRINT @sqlITPUB个人空间F0v@"Lg)m;L}
EXEC (@sql)ITPUB个人空间'A6{K_jUv4\ N

q?3cFHCW42035--获取本次任务运行抽取的最大时间ITPUB个人空间C'n!g4Q"W;J
IF DATEADD(day,1,@BeginDate)>@EndDate
9{R u\ t EANC!a42035SELECT @CurrDate = @EndDateITPUB个人空间@"|bX9f%nx H.X'\
ELSE
;j6`9D|8RaPK3D o42035SELECT @CurrDate = DATEADD(day,1,@BeginDate)

--如果@sql执行失败,同样记录状态和时间
6@Uhcci42035IF @@ERROR <> 0
/Q7H6J.S4l42035GOTO FAIL

--记录每次运行的时间运行情况,可提供相应参考ITPUB个人空间D/lESi
UPDATE ExtractTaskListITPUB个人空间j%x qNj/m.e
SET TargetDate = @CurrDate,
1Z!_UP6s;^GOn-bV42035Flag = 1
C(Ez+S$p42035WHERE UPPER(TaskName) = UPPER('test')

SELECT @BeginDate = DATEADD(DD,1,@BeginDate)

END

RETURN

FAIL:

--记录错误

UPDATE ExtractTaskList
js GQ;FFo42035SET TargetDate = @CurrDate,ITPUB个人空间X,~#z4U:KmHR1LyH
Flag = 2ITPUB个人空间$yF5uG _ y
WHERE UPPER(TaskName) = UPPER('test')

RETURN 0

END



目前,在数据仓库逻辑模型设计上主要有实体-关系建模和维度建模两种方法,其中维度建模,即星型模式设计在国内数据仓库项目工程实践中应用更为广泛。星型结构模型典型的形式是一个主题由中间的一个大表和围绕在其
周围的一组小表组成。中间的大表称为“事实表”,存储数值型度量指标和连接到维度表的外键;外围的小表称为“维度表”,存储用于描述事物的文本属性信息及连接到事实表的主键。

这一结构体现了两种关系,一是维度表与事实表之间的一对多关系;二是通过事实表体现出的维度表之间相互的多对多关系。实践证明,这种简单而对称的结构能够表达各种复杂的业务逻辑,并有助于最终用户的访问。

主外键关系是维度建模的重要基础,那么怎样决定数据仓库中的主键呢?至少有三个方面因素必须考虑:第一,主键应该是稳定的;第二,主键应该能够标识出到相关源系统的映射;第三,主键实际是一种约束,必须考虑加载和查询的效率。

维度表中的键

维度表一般由主键、分类层次和属性描述组成。对于主键的选择一般存在两种观点:一种是采用自然键(Natural Key),即操作型系统使用的具有一定内置含义的标识符;另一种是采用代理键(Surrogate Key),即由装载程序或者数据库系统所赋予的一个数值,该数值按顺序分配,没有内置含义但可以作为一行维度信息的惟一标识。

根据笔者的项目经验,推荐采纳第二种观点,主要原因是代理键简化了事实表与维度表的主外键关系。维度表作为用户进入事实表的入口,承担着记录观察视角的历史变化轨迹的任务。如果以自然键、时间标签,或许还有机构代码联合起来也可以在逻辑上惟一标识出一个产品,但如果作为主键,那就意味着在事实表中也要加入同样的外键信息,而事实表记录行数是巨大的,在多个维度上重复这样的做法会使事实表由于列宽过于膨胀而迅速崩溃。

最好的办法是采用代理键,即选择一个只占用4个字节就可以处理20亿个正整数的列作为维度表的主键,这样既解决了事实表存储空间的浪费问题,又维持了自身的独立和稳定。

另一个好处是,代理键可以作为数据仓库系统与源系统之间的缓冲。随着企业的发展,生产系统中的产品名称、产品分类、组织机构几乎不可避免地会发生调整,有的时候甚至自然键本身也会发生变化。就像身份证号码都从15位变到18位一样,在历史的长河中一般认为不可能的事其实都有可能发生。如果采用了代理键,这些变化会被屏蔽在维度表内,需要记录历史轨迹的就贴上时间标签,不需要的就直接更新掉,变化的过程不会对事实表产生任何冲击。维持业务系统的自然键与维度表代理键的对照关系的目的也在于此,既保留了业务系统到数据仓库系统的映射,又提高了数据仓库系统的抗震性。

事实表中的键

事实表中包含度量指标和连接到相关维度表的一组外键,这组外键的联合惟一标识了一行事实数据。然而,事实表在维度建模过程中是如此重要,以致于我们必须进一步认识它。这里的关键是对逻辑主键和物理主键的认识。

逻辑主键是构成事实表的所有维度外键的联合。由于事实表存在多种类型,从粒度上看有原子级和汇总级;从度量的可加性上看有完全可加、半可加和不可加类型。在数据仓库逻辑模型设计阶段,使用逻辑主键是妥当的,这是一个具有很好包容性和概括性的定义。物理主键是在具体的项目场景中能够惟一标识事实表中一行数据的列的联合。在数据仓库物理模型设计阶段,一般会采用物理主键的概念。逻辑主键有时是和物理主键一致的,但并不总是这样。

物理模型中保单事实表的物理主键已经确定,那么是否意味着一定要在事实表上真正建立起联合主键?这个问题目前在业界存在着广泛的争议。笔者认为应该视情况而定,如果事实表很大,每天的增量信息很多,那么这个联合主键可以不做显式的声明,即不在保单事实表上建立主键,物理主键只用于ETL及数据核查过程。

因为,在OLTP系统环境中,数据的完整性通常靠两种方式来保证,一是应用程序的逻辑保证,另一个是数据库结构自身的约束机制。这两种方式相互补充,而数据仓库环境中的情况则完全不同,数据仓库中数据的完整性更依赖于应用程序,也就是ETL系统的保证。

首先,ETL系统运行时间虽然很长,但其结构是简单的,重复地抓取、清洗、转换、加载动作。与其相比,OLTP系统可能同时在一张表上执行大量并行业务操作;其次,事实表的惟一入口是维度表,按照维度建模的思路实现ETL程序,只可能产生不准确的维度信息,但不可能在事实表中产生重复记录;第三,与OLTP系统相比,数据仓库系统没有交互式人机录入界面,不存在“人为”错误。

因此,当装载时间窗是一个必须考虑的问题时,建议从数据仓库环境中删除一些不必要的约束,其中包括主键约束、外键约束和惟一索引约束。这些约束规则可以在外部得以实施。 (CCW)

0 Comments:

Post a Comment

<< Home