Skip to content

数据仓库设计

约 7045 字大约 23 分钟

大数据关系型数据库

2023-11-15

定义

数据仓库(Data Warehouse),可简写为 DW 或 DWH。数据仓库的目的是构建面向分析的集成化数据环境,为企业提供决策支持(Decision Support)。它出于分析性报告和决策支持目的而创建。

数据仓库基本特征

数据仓库是面向主题的、集成的、非易失的和时变的数据集合,用以支持管理决策。

面向主题

传统数据库中,最大的特点是面向应用进行数据的组织,各个业务系统可能是相互分离的,而数据仓库则是面向主题的。主题通常指的是一个特定的商业问题领域或业务领域,可以是跨越不同部门和业务领域的。它们反映了企业运营的不同方面,可以帮助企业更好地了解整个业务运营的全貌和趋势、进行数据分析、决策支持和业务优化。

集成性

通过对分散、独立、异构的数据库数据进行抽取、清理、转换和汇总便得到了数据仓库的数据,这样保证了数据仓库内的数据关于整个企业的一致性。

数据仓库中的综合数据不能从原有的数据库系统直接得到。因此在数据进入数据仓库之前,必然要经过统一与综合。这一步是数据仓库建设中最关键、最复杂的一步,所要完成的工作有:

  • 统一源数据中所有矛盾之处。如字段的同名异义、异名同义、单位不统一、字长不一致等等。
  • 进行数据综合和计算。数据仓库中的数据综合工作可以在从原有数据库抽取数据时生成。但许多是在数据仓库内部生成的,即进入数据仓库以后进行综合生成的。

非易失性(不可更新性)

数据仓库的数据反映的是一段相当长的时间内 历史数据的内容,是不同时点的数据库快照的集合,以及基于这些快照进行统计、综合和重组导出的数据。

数据非易失性主要是针对应用而言。数据仓库的用户对数据的操作大多是数据查询或比较复杂的挖掘,一旦数据进入数据仓库以后,一般情况下被较长时间保留。数据仓库中一般有大量的查询操作,但修改和删除操作很少。因此,数据经加工和集成进入数据仓库后是极少更新的。通常只需要定期的加载和更新

时变性

数据仓库包含各种粒度的历史数据。数据仓库中的数据可能与某个特定日期、星期、月份、季度或者年份有关。数据仓库的目的是通过分析企业过去一段时间业务的经营状况,挖掘其中隐藏的模式。虽然数据仓库的用户不能修改数据,但并不是说数据仓库的数据是永远不变的。分析的结果只能反映过去的情况,当业务变化后,挖掘出的模式会失去时效性。因此数据仓库的数据需要更新,以适应决策的需要。从这个角度讲,数据仓库建设是一个项目,更是一个过程。数据仓库的数据随时间的变化表现在以下几个方面:

  1. 数据仓库的数据时限一般要远远长于操作型数据的数据时限。
  2. 操作型系统存储的是当前数据,而数据仓库中的数据是历史数据。
  3. 数据仓库中的数据是按照时间顺序追加的,它们都带有时间属性。

数据仓库与数据库

数据库与数据仓库的区别实际讲的是 OLTP 与 OLAP 的区别。

操作型处理,叫联机事务处理 OLTP(On-Line Transaction Processing),也可以称面向交易的处理系统。它是针对具体业务在数据库联机的日常操作,通常对少数记录进行查询、修改。用户较为关心操作的响应时间、数据的安全性、完整性和并发支持的用户数等问题。传统的数据库系统作为数据管理的主要手段,主要用于操作型处理,像 Mysql,Oracle 等关系型数据库一般属于OLTP。

分析型处理,叫联机分析处理 OLAP(On-Line Analytical Processing)一般针对某些主题的历史数据进行分析,支持管理决策。

要明白,数据仓库的出现,并不是要取代数据库。数据库是面向事务的设计,数据仓库是面向主题设计的。数据库一般存储业务数据,数据仓库存储的一般是历史数据。数据库设计是尽量避免冗余,一般针对某一业务应用进行设计。比如一张简单的 User 表,记录用户名、密码等简单数据即可。符合业务应用,但是不符合分析。数据仓库在设计是有意引入冗余,依照分析需求,分析维度、分析指标进行设计

区别

数据库是为捕获数据而设计,数据仓库是为分析数据而设计。

数据仓库是在数据库已经大量存在的情况下,为了进一步挖掘数据资源和决策需要而产生的。它决不是所谓的"大型数据库"。

数据仓库分层

数据仓库中的数据分层原则是一种组织数据的方法,旨在支持不同层次的数据分析和查询需要。一般采用如下分层结构:

数据仓库分层
数据仓库分层

数据源层:ODS(Operational Data Store)

ODS 层,是最接近数据源中数据的一层。为了考虑后续可能需要追溯数据问题,因此对于这一层就不建议做过多的数据清洗工作。原封不动地接入原始数据 即可。至于数据的去噪、去重、异常值处理等过程可以放在后面的 DWD 层来做。

数据仓库层:DW(Data Warehouse)

数据仓库层是我们在做数据仓库时要核心设计的一层。在这里,从 ODS 层中获得的数据按照主题建立各种数据模型。

DW 层又细分为 DWD(Data Warehouse Detail)层、DWM(Data WareHouse Middle)层和 DWS(Data WareHouse Servce) 层。

数据明细层:DWD(Data Warehouse Detail)

该层一般保持和 ODS 层一样的数据粒度,并且提供一定的数据质量保证。DWD 层要做的就是将数据清理、整合、规范化。脏数据、垃圾数据、规范不一致的、状态定义不一致的、命名不规范的数据都会被处理

同时,为了提高数据明细层的易用性,该层会采用一些维度退化手法,将维度退化至事实表中,减少事实表和维表的关联。另外,在该层也会做一部分的数据聚合。将相同主题的数据汇集到一张表中,提高数据的可用性。

数据中间层:DWM(Data WareHouse Middle)

该层会在 DWD 层的数据基础上对数据做轻度的聚合操作。生成一系列的中间表,提升公共指标的复用性,减少重复加工。

直观来讲,就是对通用的核心维度进行聚合操作,算出相应的统计指标

在实际计算中,如果直接从 DWD 或者 ODS 计算出宽表的统计指标,会存在计算量太大并且维度太少的问题。因此一般的做法是:在 DWM 层先计算出多个小的中间表,然后再拼接成一张 DWS 的宽表。由于宽和窄的界限不易界定,也可以去掉 DWM 这一层,只留 DWS 层,将所有的数据再放在 DWS 亦可。

数据服务层:DWS(Data WareHouse Servce)

DWS 层为公共汇总层,会进行轻度汇总,粒度比明细数据稍粗。基于 DWD 层上的基础数据,整合汇总成分析某一个主题域的服务数据,一般是宽表。DWS 层应覆盖 80% 的应用场景。又称数据集市或宽表。

按照业务划分,如主题域流量、订单、用户等,生成字段比较多的宽表。用于提供后续的业务查询,OLAP 分析,数据分发等。

一般来讲,该层的数据表会相对比较少。一张表会涵盖比较多的业务内容,由于其字段较多,因此一般也会称该层的表为宽表。

数据应用层:APP(Application)

在这里,主要是提供给数据产品和数据分析使用的数据。一般会存放在 ES、PostgreSql、Redis 等系统中供线上系统使用,也可能会存在 Hive 或者 Druid 中供数据分析和数据挖掘使用。比如我们经常说的报表数据,一般就放在这里。

数据仓库架构

主要的数据仓库架构:Inmon 企业工厂架构、Kimball 数据仓库架构、混合型数据仓库架构。

Inmon 企业工厂架构

Inmon 企业工厂架构流程图
Inmon 企业工厂架构流程图

上图的前两步不过多介绍,直接从第三步开始。

  • 企业级数据仓库。是该架构中的核心组件。正如 Inmon 数据仓库所定义的,企业级数据仓库是一个细节数据的集成资源库。其中的数据以最低粒度级别被捕获,存储在满足三范式设计的关系数据库中。
  • 部门级数据集市。是面向主题数据的部门级视图,数据从企业级数据仓库获取。数据在进入部门数据集市时可能进行聚合。数据集市使用多维模型设计,用于数据分析。重要的一点是,所有的报表工具、BI 工具或其他数据分析应用都从数据集市查询数据,而不是直接查询企业级数据仓库。

Kimball 数据仓库架构

Kimball 数据仓库架构
Kimball 数据仓库架构

对比上一张图可以看到,Kimball 与 Inmon 两种架构的主要区别在于核心数据仓库的设计和建立。

Kimball 的数据仓库包含高粒度的企业数据,使用多维模型设计。这也意味着 数据仓库由星型模式的维度表和事实表构成。分析系统或报表工具可以直接访问多维数据仓库里的数据。在此架构中的数据集市也与 Inmon 中的不同。这里的 数据集市是一个逻辑概念,只是多维数据仓库中的主题域划分,并没有自己的物理存储,也可以说是虚拟的数据集市。

混合型数据仓库架构

所谓的混合型结构,指的是在一个数据仓库环境中 联合使用 Inmon 和 Kimball 两种架构

混合型数据仓库架构
混合型数据仓库架构

从架构图可以看到,这种架构将 Inmon 方法中的数据集市部分替换成了一个多维数据仓库,而数据集市则是多维数据仓库上的逻辑视图。使用这种架构的好处是既可以利用规范化设计消除数据冗余,保证数据的粒度足够细。又可以利用多维结构更灵活地在企业级实现报表和分析。

数仓建设模式

DW 层进行数仓建模,常见的是范式建模法、维度建模法。每种方法从本质上将是从不同的角度看待业务中的问题。

范式建模法(Third Normal Form,3NF)

范式建模法其实是我们在构建数据模型常用的一个方法。该方法的主要由 Inmon 所提倡。主要解决关系型数据库的数据存储,利用的一种技术层面上的方法。目前,我们在关系型数据库中的建模方法,大部分采用的是三范式建模法。

范式是符合某一种级别的关系模式的集合。构造数据库必须遵循一定的规则,而在关系型数据库中这种规则就是范式,这一过程也被称为规范化。目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、Boyce-Codd 范式(BCNF)、第四范式(4NF)和第五范式(5NF)。

在数据仓库的模型设计中,一般采用第三范式。一个符合第三范式的关系必须具有以下三个条件:

  • 每个属性值唯一,只包含单一值,不可再分解。
  • 每个属性必须完全依赖于整个主键,而非主键的一部分。
  • 非主键列之间不能存在传递依赖关系。每个属性不能依赖于其他关系中的属性。

如果想要了解更多关于范式的内容可以查看我的另一篇文章:如何求解数据库闭包、候选码和范式?

维度建模法(Dimensional Modeling)

维度模型是数据仓库领域另一位大师 Ralph Kimball 所倡导。他的《数据仓库工具箱》是数据仓库工程领域最流行的数仓建模经典。维度建模以分析决策的需求出发构建模型,构建的数据模型为分析需求服务,因此它重点解决用户如何更快速完成分析需求,同时还有较好的大规模复杂查询的响应性能。

维度建模法

这个模型很好的均衡了查询复杂度与数据的维护成本。

对于查询来说,最简单的模型是一张超宽的业务表,所有的查询条件都有对应的表内字段,不需要任何 JOIN。但坏处是这张表的维护成本很高,有大量的冗余数据,经常要修改表结构或是现有数据来适应业务的变化。对于数据库管理员来说,这张表就是一场灾难。而范式模型是另一个极端,表的维护成本低,没有冗余数据,但对于统计查询不友好。业务人员不但要理解错综复杂的表与表之间的网状关系,而且构建统计查询的 SQL 语句的难度也很大,还要忍受复杂 SQL 语句低下的执行效率。

维度模型就是这两者之间的一个折中。对业务人员来说,查询时有统一的语句结构,并且最多只有一级 JOIN。对维护人员来说,为应对业务需求的变化,大部分数据表的更改都发生在数据量较小的维度表上。

维度模型
维度模型

典型的代表是我们比较熟知的星形模型(Star-schema),以及在一些特殊场景下适用的雪花模型(Snow-schema)。

维度建模中比较重要的概念就是事实表(Fact table)和维度表(Dimension table)。

  1. 事实表。必然存在的一些数据,像采集的日志文件,订单表,都可以作为事实表。特征:是一堆主键的集合。每个主键对应维度表中的一条记录,根据主题确定出需要使用的数据。
  2. 维度表。维度就是所分析的数据的一个量,维度表就是以合适的角度来创建的表。

事实表

发生在现实世界中的操作型事件。事实表是维度模型的中枢,在设计事实表时最主要有两个问题:定义指标和确定每条记录的粒度。

指标:大部分情况下都是数字。如果出现文本的指标,则该考虑一下它到底是指标还是维度。在分析统计中,我们会对指标数据做各种聚合,比如计算总和、平均数、中位数等等。根据对聚合操作的支持,我们可以把指标分为可加、半可加与不可加。

粒度:事实表中每条记录的粒度越小,在其之上的统计分析就越精细。所以一般来讲,我们都会以业务中最小的原子事务为粒度来构建事实表。事实表设计的另一个重要原则是要保证表中每一条记录的粒度是相同的。粒度不同容易出现错误的统计结果。

事实表表示对分析主题的度量。比如一次购买行为我们就可以理解为是一个事实。

事实表
事实表

图中的订单表就是一个事实表。你可以理解他就是在现实中发生的一次操作型事件。我们每完成一个订单,就会在订单中增加一条记录。事实表的特征:表里没有存放实际的内容,他是一堆主键的集合,这些 ID 分别能对应到维度表中的一条记录。事实表包含了与各维度表相关联的外键,可与维度表关联。事实表的度量通常是数值类型,且记录数会不断增加,表数据规模迅速增长。

事实表的 3 个基本类型:

  1. 事务事实表。表中的一行对应空间或时间上某点的度量事件。就是一行数据中必须有度量字段,即指标。比如说销售金额,销售数量等这些可加的或者半可加就是度量值。另一点就是事务事实表都包含一个与维度表关联的外键。并且度量值必须和事务粒度保持一致。
  2. 周期快照事实表。周期事实表就是每行都带有时间值字段,代表周期。通常时间值都是标准周期,如某一天,某周,某月等。粒度是周期,而不是个体的事务,也就是说一个周期快照事实表中数据可以是多个事实,但是它们都属于某个周期内。
  3. 累积快照事实表。周期快照事实表是单个周期内数据,保留先前的快照。而累计快照事实表是由多个周期数据组成,每行汇总了过程开始到结束之间的度量,计算累计值,反映当前状态和度量。每行数据相当于管道或工作流,有事件的起点,过程,终点,并且每个关键步骤都包含日期字段。

维度表

每个维度表都包含单一的主键列。维度表的主键可以作为与之关联的任何事实表的外键,维度表通常比较宽,是扁平型非规范表,包含大量的低粒度的文本属性。

维度表示你要对数据进行分析时所用的一个量。比如你要分析产品销售情况,你可以选择按类别来进行分析,或按区域来分析。每个类别就构成一个维度。上图中的用户表、商家表、时间表这些都属于维度表,这些表都有一个唯一的主键,然后在表中存放了详细的数据信息。

总的说来,在数据仓库中不需要严格遵守规范化设计原则。因为数据仓库的主导功能就是面向分析,以查询为主,不涉及数据更新操作。事实表的设计是以能够正确记录历史信息为准则,维度表的设计是以能够以合适的角度来聚合主题内容为准则

  • 维度表结构。

    维度表谨记一条原则:包含单一主键列。但有时因业务复杂,也可能出现联合主键,请尽量避免。如果无法避免,也要确保必须是单一的,这很重要。如果维表主键不是单一的,那么和事实表关联时会出现数据发散,导致最后结果可能出现错误。维度表通常比较宽,包含大量的低粒度的文本属性。

  • 事实数值作为维度表属性。

    涉及计算的数值应该放入事实表。涉及约束、分组和标记的数据应该放在维度表中,如商品价格。

  • 跨表钻取。

    跨表钻取意思是当每个查询的行头都包含相同的一致性属性时,使不同的查询能够针对两个或更多的事实表进行查询。钻取可以改变维的层次,变换分析的粒度。它包括上钻/下钻。

  • 退化维度。

    退化维度就是将维度退回到事实表中。因为有时维度除了主键没有其他内容。虽然也是合法维度键,但是一般都会退回到事实表中,减少关联次数,提高查询性能。

  • 多层次维度。

    多数维度包含不止一个自然层次,如日期维度可以从天的层次到周到月到年的层次。所以在有些情况下,在同一维度中存在不同的层次。

  • 维度表空值属性。

    当给定维度行没有被全部填充或者当存在属性没有被应用到所有维度行时,将产生空值维度属性。上述两种情况,推荐采用描述性字符串代替空值,如使用 unknown 或 not applicable 替换空值。

  • 日历日期维度。

    在日期维度表中,主键的设置不要使用顺序生成的 id 来表示,可以使用更有意义的数据表示。比如将年月日合并起来表示,即 YYYYMMDD,或者更加详细的精度。

  • 支架表。

    支架表(Bridge Table)是用于解决维度表多对多关系的一种表结构。如产品和市场的关系。支架表可以节省空间、可以确保一致性,但是它引入了更多的连接,降低系统性能,也不易用户理解和浏览。

维度建模三种模式

星型模式

星形模式(Star Schema)是最常用的维度建模方式。星型模式是以事实表为中心,所有的维度表直接连接在事实表上,像星星一样。星形模式的维度建模由一个事实表和一组维表成,且具有以下特点:

  • 维表只和事实表关联,维表之间没有关联。
  • 每个维表主键为单列,且该主键放置在事实表中,作为两边连接的外键。
  • 以事实表为核心,维表围绕核心呈星形分布。
星型模式
星型模式

雪花模式

雪花模式(Snowflake Schema)是对星形模式的扩展。雪花模式的维度表可以拥有其他维度表的。虽然这种模型相比星型更规范一些,但是由于这种模型不太容易理解,维护成本比较高。而且性能方面需要关联多层维表,性能也比星型模型要低,所以一般不是很常用。

雪花模式
雪花模式

星座模式

星座模式是星型模式延伸而来。星型模式是基于一张事实表的,而 星座模式是基于多张事实表的,而且共享维度信息。前面介绍的两种维度建模方法都是多维表对应单事实表,但在很多时候维度空间内的事实表不止一个,而一个维表也可能被多个事实表用到。在业务发展后期,绝大部分维度建模都采用的是星座模式。

星座模式
星座模式

维度建模过程

维度建模过程
维度建模过程

维度建模四步走,不管什么业务,就按照这个步骤来,顺序不要搞乱。因为这四步是环环相扣,步步相连。下面详细拆解下每个步骤怎么做。

  1. 选择业务过程。

    维度建模是紧贴业务的,所以必须以业务为根基进行建模。那么选择业务过程,顾名思义就是在整个业务流程中选取我们需要建模的业务,根据运营提供的需求及日后的易扩展性等进行选择业务。比如商城,整个商城流程分为商家端,用户端,平台端,运营需求是总订单量,订单人数,及用户的购买情况等,我们选择业务过程就选择用户端的数据,商家及平台端暂不考虑。业务选择非常重要,因为后面所有的步骤都是基于此业务数据展开的。

  2. 声明粒度。

    声明粒度意味着精确定义某个事实表的每一行代表什么。先举个例子:对于用户来说,一个用户有一个身份证号,一个户籍地址,多个手机号,多张银行卡,那么与用户粒度相同的粒度属性有身份证粒度,户籍地址粒度,比用户度更细的粒度有手机号粒度,银行卡粒度,存在一对一的关系就是相同粒度。为什么要提相同粒度呢,因为维度建模中要求我们,在 同一事实表 中,必须具有 相同的粒度,同一事实表中不要混用多种不同的粒度,不同的度数据建立不同的事实表。并且从给定的业务过程获取数据时,强烈建议从关注原子粒度开始设计,也就是从最细粒度开始。因为原子粒度能够承受无法预期的用户查询。但是上卷汇总粒度对查询性能的提升很重要的,所以对于明确需求的数据,我们建立针对需求的上卷汇总粒度,对需求不明朗的数据我们建立原子粒度。

  3. 确认维度。

    维度要解决的问题是业务人员如何描述业务过程数据,粒度清楚,维度通常比较容易确定,因为它表示的是“谁?什么?何处?何时?如何?”。维度集合决定了事实表每行数据中的度量。常见的维度如日期、产品、客户等,每个维度表应该包括所有的描述当前维度的属性。

  4. 确认事实。

    事实表是用来度量的,基本上都以数量值表示。事实表中的每行对应一个度量,每行中的数据是一个特定级别的细节数据,称为粒度。维度建模的核心原则之一是 同一事实表中的所有度量必须具有相同的粒度。这样能确保不会出现重复计算度量的问题。有时候往往不能确定该列数据是事实属性还是维度属性。记住最实用的事实就是数值类型和可加类事实,如成本金额、订货数量等。所以可以通过分析该列是否是一种包含多个值并作为计算的参与者的度量,这种情况下该列往往是事实。




贡献者

更新日志

2025/3/4 07:53
查看所有更新日志
  • 4cc96-improve(docs): use chinese punctuation
  • 1ca4c-improve(docs): use chinese punctuation
  • 1289a-improve(docs): delete extra whitespace and blank lines
  • c2111-modify(docs): remanage folders and rename files
  • 96e66-docs: update docs
  • 8f99a-整理图片和文章
  • e33f4-整理tag
  • f86ee-update
  • 93933-新增文字+CRLF全部替换为LF
  • 547bb-升级主题+新增文章+修改格式

Keep It Simple