数据仓库-维度

各维度类型

渐变维

描述

渐变维(SCD. Slowly Change Dimension,是一种在多维数据仓库中实现维度历史的技术

类型

  • SCD1

通过更新维度记录直接覆盖已存在的值,它不维护记录的历史

一般用于修改错误的数据

  • SCD2

在源数据发生变化时,给维度记录建立一个新的版本记录,从而维护维度历史。

不删除、修改已存在的数据,新增一条数据

  • SCD3

通常用作保持维度记录的几个版本。通过给某个数据单元增加多个列来维护历史。

例如,为了记录客户地址的变化,customer_dim维度表有一个customer_address列和一个previous_customer_address列,分别记录当前和上一个版本的地址。

SCD3可以有效维护有限的历史,而不像SCD2那样保存全部历史。

很少使用,只适用于数据的存储空间不足并且用户接受有限维度历史的情况

维度子集

由来

有些需求不需要最细节的数据。

想要某个月的销售汇总,而不是某天的数据

相对于全部的销售数据,只对某些特定状态的数据更感兴趣

事实数据需要关联到特定的维度,这些特定维度包含在从细节维度选择的行中,所以叫维度子集。

维度子集比细节维度的数据少,因此更易使用,查询也更快

描述

子维度是一种一致性维度,由基本维度的列与行的子集构成。

细节维度称为基本维度,维度子集称为子维度

基本维度表与子维度表具有相同的属性或内容,这样的维度表具有一致性。

一致的维度具有一致的维度关键字、属性列名字、属性定义以及属性值。

当构建聚合事实表,或者需要获取粒度级别较高的数据时,需要用到子维度。

类型

  • 包含属性子集的子维度

当事实表获取比基本维度更高粒度级别的度量时,需要上卷到子维度

基本维度和子维度表的主键是不同的

比如,日数据上卷到月数据

  • 包含行子集的子维度

基本维度和子维度具有同样粒度级别的细节数据

基本维度和子维度表的主键是相同的

比如,基本维度表中包含多种类型的数据,现在只想根据其中某一类型的数据做统计

  • 视图维度子集

优点

不真实存储物理数据,不需要额外的存储空间

可规避数据不一致的潜在风险

减少数据冗余

缺点

当基本维度表和子维度表的数据量相差悬殊时,性能会比物理表差很多

如果定义的视图的查询很复杂,并且视图很多的话,可能会对元数据存储系统造成压力,严重影响查询性能。

视图是只读的,不能对视图使用LOADINSERT语句装载数据

一旦视图建立,它的结构就是固定的,之后底层表的结构改变,不会反映到视图的结构中。

角色扮演维度

描述

单个物理维度可以被事实表多次引用,每个引用连接逻辑上存在差异的角色维度

当一个事实表多次引用一个维度表时会用到角色扮演维度。

例如,事实表可以有多个日期,每个日期通过外键引用不同的日期维度,原则上每个外键表示不同的日期维度视图,这样引用具有不同的含义。这些不同的维度视图具有唯一的代理键列名,被称为角色,相关维度被称为角色扮演维度

层次维度

描述

大多数维度都具有一个或多个层次。如:日期维度就有四级层次:年、季度、月和日。

日期维度是一个单路径层次,因为除了年-季度--日这条路径外,它没有任何其它层次。

举例

日期维度:年-季度--

地理位置维度:国家---

类型

固定深度的层次
描述

固定深度层次是一种一对多关系

当固定深度层次定义完成后,层次就具有固定的名称,层次级别作为维度表中的不同属性出现。

固定层次能够提供可预测的、快速的查询性能,可以在固定深度层次上进行分组和钻取查询

如:一年中有四个季度,一个季度包含三个月等

查询类型

l  分组查询

把度量按照一个维度的一个或多个级别进行分组聚合。

SELECT product_category, year, quarter, month, sum(order_amount) as s_amount FROM sales_order_fact a, product_dim b, date_dim c WHERE a.product_sk = b.product_sk AND a.order_date_sk = c.date_sk GROUP BY product_category, year, quater, month CLUSTER BY product_category, year, quater, month

l  钻取查询

把度量按照一个或多个级别进行分组。与分组查询不同的是,分组查询只显示分组后最低级别,即示例中每月的度量汇总值,而钻取查询显示分组后维度每一个级别的度量。

union all

SELECT
product_category, time, order_amount
FROM (
SELECT
product_category,
CASE WHEN sequence = 1 THEN CONCAT('year: ', time)
 WHEN sequence = 2 THEN CONCAT('quarter: ', time)
 ELSE CONCAT('month: ', time) END time,
order_amount, sequence, date
FROM(
SELECT
product_category, MIN(date) date, year time, 1 sequence, SUM(order_amount) order_amount
FROM sales_order_fact a, product_dim b, date_dim c
WHERE a.product_sk = b.product_sk and a.order date_sk = c.date_sk
GROUP BY product_category, year
UNION ALL
SELECT
product_category, MIN(date) date, quarter time, 2 sequence,SUM(order_amount) order_amount
FROM sales_order_fact a, product_dim b, date_dim c
WHERE a.product_sk = b.product_sk and a.order date_sk = c.date_sk
GROUP BY product_category, year, quarter
UNION ALL
SELECT product_category, MIN(date) date, month time, 3 sequence,SUM(order_amount) order_amount
FROM sales order fact a, product dim b,date dim c
WHERE a.product_sk . b.product_sk and a.order date_sk = c.date_sk
GROUP BY product_category, year , quarter , month
) x
CLUSTER BY product_category , date , sequence , time
) y;

使用union all集合操作将年、季度、月三个级别的汇总数据联合成一个结果集。注意union all的每个 查询必须包含相同个数和类型的字段。附加的min(date)sequence导出列用于对输出结果排序显示

grouping__id

SELECT
product_category, time, order_amount
FROM (
SELECT
product_category,
CASE WHEN gid = 3 THEN CONCAT('year: ', year)
 WHEN gid = 7 THEN CONCAT('quarter: ', quarter)
 ELSE CONCAT('month: ', month) END time ,
order_amount, gid, date
FROM(
SELECT
product_category,year,quarter,month,MIN(date) date, SUM(order_amount) order_amount, cast(grouping__id as int) gid
FROM sales_order_fact a, product dim b, date dim c
WHERE a.product_sk = b.product_sk and a.order_date_sk = c.date_sk
GROUP BY product_category, year , quarter,month WITH ROLLUP
) x WHERE gid > 1
CLUSTER BY product_category , date , gid , time
) y;

使用HiveQL提供的grouping__id函数(注意是两个下划线)和with rollup子句。rollup会生成按产品类型、年、季度、月及其所有分组的聚合数据行。 with rollupSQL中通用的语法,它只能和group by语句一同使用。rollup子句常被用于计算一个维度中各个层级的聚合数据

select a, b, c, sum(d) from tab1 group by a, b, c with rollup ;
select a, b, c, sum(d) from tab1 group by a, b, c
union all
select a, b, null, sum(d) from tab1 group by a, b, null
union all
select a, null, null, sum(d) from tab1 group by a, null, null
union all
select null, null, null, sum(d) from tab1 ;

group by后面不跟任何列求sum时,abc三列在聚合数据行会显示为null。当列本身具有null值时,就会产生混淆,无法区分查询结果中的null值是属 于列本身的还是聚合的结果行,因此需要一种方法识别出列中的null值。grouping_id函数就是此场景下的解决方案。 这个函数为每种聚合数据行生成唯一的组id。它的返回值看起来像整型数值,其实是字符串类型,这个值使用了位图策略(bitvector,位向量),即它的二进制形式中 的每一位表示对应列是否参与分组,如果某一列参与了分组,对应位就被置为1,否则为0。通过这种方式可以区分出数据本身中的null值。

递归(父子关系)

数据仓库中的关联实体经常表现为一种“父—子”关系

在这种类型的关系中,一个父亲可能有多个孩子,而一个孩子只能属于一个父亲。例如,通常一名企业员工只 能被分配到一个部门,而一个部门会有很多员工。“父—子”之间形成一种递归型树结构,是一种比较理想和灵活的存储层次关系的数据结构

多路径层次

描述

多路径层次是对单路径层次的扩展

如:数据仓库的月维度只有一条层次路径,即年-季度-月,新增一个 促销期,加一个年-促销期-月的层次路径。这时月维度将有两条层次路径,因此是多路径层次维度

参差不齐的层次

描述

上述例子中有的月份无促销期

退化维度

描述

此技术可减少维度的数量,简化维度数据仓库模式,也有更好的查询性能

维度表中除了业务主键外没有其他内容,如:销售订单中,订单维度表除了订单号,没有任何其他属性,而订单号是事务表的主键

杂项维度

描述

杂项维度就是一种包含的数据具有很少可能值的维度。

事务型商业过程通常产生一系列混杂的、低基数的标志位或状态信息。与其为每个标志或属性定义不同的维度,不如建立单独的将不同维度合并到一起的杂项维度。

属性可能很多,但是每种属性的可能值很少,只包含小范围的离散值。

如:yes/no. 1/2

解决

  • 忽略这些标志和指标
  • 保持事实表行中的标志位不变
  • 不建立对应的维表
  • 将每个标志位放入其自己的维度中
  • 在装载事实表数据前先处理这四个维度表,必要时生成新的代理键,然后在事实表中引用这些代理键
  • 将杂项维度当作普通维度来处理,多数情况下不合适

经验值:外键的数量不超过20

  • 杂项维度

杂项维度能够合理地存放离散属性值,还能够维持其他主要维度地存储空间

杂项维度是低基数标志和指标的分组。通过建立杂项维度,可以将标志和指标从事实表中移出,并将它们放入到有用的多维框架中

对杂项维度数据量的估算也会影响其建模策略

如:某个简单的杂项维度包含10个二值标识,现金或信用卡支付类型、是否审核、在线或离线、是否海外等,最多将包含1024(2^10)行。每个标志都与其他标志一起发生作用,在这种情况下,浏览单一维度内的标识可能没什么意义。

数据量不多,可预装载,根据所有组合的笛卡尔积建立行

数据量太多,可根据事实表数据动态装载

维度合并

描述

使用桥接表,将一个多对多关系转化为两个一对多关系。

事实表通过引用桥接表的一个代理键,同时关联到多个维度值,这样做的目的是消除数据冗余,保证数据一致性

实现

将多对多关系根据笛卡尔积生成数据,并添加唯一标识列(主键)

分段维度

描述

有一些能够定义成包含连续值的分段,例如年龄和收入这种数值型的属性,就可以分 成连续的数值区间,而像状态这种描述性的属性,可能需要用户根据自己的实际业务仔细定义,通常定义的根据是某种可度量的数值

原文地址:https://www.cnblogs.com/EnzoDin/p/14197901.html