Fan Trap 简析
BO Universe设计的时候对表关联的设计有两种情况需要注意和避免的: Chasm Trap和Fan Trap.
前者是在一种典型情况下,如一个Dimension同时与两个FCT表进行一对多连接的时候,如果FCT里面包含Measure和Dimension/Detial 对象的时候,select也包含Dimension,查询结果里面出现dimension的笛卡尔集,导致measure被错误的累计成一个很大的值: 如
(正常情况,对于Orders聚合结果应该使400, Loans聚合结果可能是150)
这种情况比较容易理解。 BO提供了多种方法解决:
1) 对每个fact表建独立的context;
2) 限制每个measure用独立的sql 查询;
3) 分universe, 一个universe对应一个fact;
后者稍微有点抽象(可能只是对我来说比较陌生):
如果一个dimension一对多连接另一个fact, 然后一个fact再以一对多方式连接第三个fact. 如下图:
此时对于第二层的fact表聚合就会出现FAN Trap,但这种情况只对贪心的人有效,比如你希望用一条SQL做聚合操作,得到两个fact表中measure信息:
自己设计一个例子:
DROP TABLE City purge;
DROP TABLE City_Type purge;
DROP TABLE Customers purge;
CREATE TABLE City
(
ID INTEGER NULL ,
CUST_ID INTEGER NULL ,
CITY_NAME VARCHAR2(20) NULL ,
RENT_INCOME INTEGER NULL
);
CREATE TABLE City_Type
(
ID INTEGER NULL ,
CITY_ID INTEGER NULL ,
CITY_TYPE CHAR(18) NULL ,
GDP_FROM_AREA INTEGER NULL
);
CREATE TABLE Customers
(
ID INTEGER NULL ,
CUST_NAME VARCHAR2(20) NULL
);
insert into Customers values (1,'JEFF');
insert into Customers values (2,'LARRY');
insert into Customers values (3,'BILL');
INSERT INTO City values (1,1,'SH',1000);
INSERT INTO City values (2,1,'BJ',1500);
INSERT INTO City values (3,1,'SY',2500);
INSERT INTO City values (4,1,'SH',500);
INSERT INTO City values (5,2,'WH',1200);
INSERT INTO City values (5,2,'SH',600);
INSERT INTO City values (5,2,'SZ',100);
INSERT INTO city_type values (1,1,'LOV',1000000);
INSERT INTO city_type values (2,2,'LOV',1200000);
INSERT INTO city_type values (3,2,'LOV',1080000);
INSERT INTO city_type values (4,3,'LOV',1300000);
INSERT INTO city_type values (5,3,'LOV',1600000);
INSERT INTO city_type values (6,5,'LOV',900000);
INSERT INTO city_type values (7,6,'LOV',2000000);
INSERT INTO city_type values (8,7,'LOV',1100000);
--- 然后看下面的query:
SELECT
a.CUST_NAME,
sum(b.RENT_INCOME),
sum(c.GDP_FROM_AREA)
FROM
CUSTOMERS a,
CITY b,
CITY_TYPE c
where a.id=b.cust_id
and b.id=c.city_id
and a.cust_name='JEFF'
group by a.cust_name;
CUST_NAME SUM(B.RENT_INCOME) SUM(C.GDP_FROM_AREA)
-------------------- ------------------ --------------------
JEFF 9000 6180000
9000 这个值显然是被重复累加过的结果,那他正确的情况应该是多少呢?看下面的查询:
SELECT
a.CUST_NAME,
b.RENT_INCOME,
c.GDP_FROM_AREA
FROM
CUSTOMERS a,
CITY b,
CITY_TYPE c
where a.id=b.cust_id
and b.id=c.city_id
and a.cust_name='JEFF'
--group by a.cust_name;
CUST_NAME RENT_INCOME GDP_FROM_AREA
-------------------- ----------- -------------
JEFF 1000 1000000
JEFF 1500 1080000
JEFF 1500 1200000
JEFF 2500 1600000
JEFF 2500 1300000
5 rows selected.
1500和2500重复了2次,所以正确结果应该是1000+1500+2500 = 5000.
所以FAN Trap实际上就是context中间表中包含measure,而且又是一对多的方式被dimension连接.
而解决FAN Trap这个问题的方法也比较简单,即对每个measure使用多重sql,但这个方法并不适用于维对象,如果是这种情况最好考虑使用多重universe的方法。
转载于:https://blog.51cto.com/mengya520/331640