2

我想通过在关系数据库 (ROLAP) 中使用星型模式来构建一个简单的多维数据模型。为此,我创建了一个事实表和两个维度表。首先,我从操作源复制数据并处理这些数据(一些简化的 ETL 过程)。

在我的模型中只有两个维度:datestatus。度量:某些状态的数量(一段时间)。

时间维度表:

CREATE TABLE [dbo].[tbl_date_dim] (    
    [ID][int]       IDENTITY(1,1) NOT NULL,
    [date_key][int] NOT NULL primary key,
    [Year][int]     NOT NULL,
    [Month][int]    NOT NULL,
    [Day][int]      NOT NULL        
);

有一个表——tbl_application其中存储了整个时间范围(字段VersionDate)。因此,我这样填写的时间维度表:

INSERT INTO [dbo].[tbl_date_dim] 
    ([date_key], 
    [Year], 
    [Month], 
    [Day]) 
(
  SELECT DISTINCT
    CAST(YEAR(VersionDate) as VARCHAR(4)) + 
    RIGHT('00' + CAST(MONTH(VersionDate) as VARCHAR(2)) ,2) +
    RIGHT('00' + CAST(DAY(VersionDate) as VARCHAR(2)), 2) as 'date_key',
    YEAR(inner_data.VersionDate)    as 'Year',
    MONTH(inner_data.VersionDate)   as 'Month', 
    DAY(inner_data.VersionDate)     as 'Day'
  FROM (
        SELECT 
            VersionDate 
        FROM [dbo].[tbl_application]
  ) AS inner_data
);

状态维度表:我使用整个现有表tbl_applicationstatus

接下来,我创建一个事实表。它包含维度表和度量的外键。

CREATE TABLE [dbo].[tbl_olap_fact] (
    [ID][int] IDENTITY(1,1) NOT NULL,    

    [status_id][int] NOT NULL,           // FK  
    [date_dim][int] NOT NULL,            // FK

    [staus_name] varchar(100) NOT NULL, // Non additive measure
    [transaction_id][int] NOT NULL,     // Additive measure

    CONSTRAINT [PK_tbl_olap_fact] PRIMARY KEY CLUSTERED
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];

transaction_id- 这个字段,我将汇总(状态数)。

接下来,我添加事实表和维度表之间的关系:

ALTER TABLE [dbo].[tbl_olap_fact] ADD CONSTRAINT [FK_tbl_olap_fact_tbl_date_dim] FOREIGN KEY([date_dim])
REFERENCES [dbo].[tbl_date_dim] ([date_key]);

ALTER TABLE [dbo].[tbl_olap_fact] ADD CONSTRAINT [FK_tbl_olap_fact_tbl_applicationstatus] FOREIGN KEY([status_id])
REFERENCES [dbo].[tbl_applicationstatus] ([ID]);

然后我填写事实表:

INSERT INTO [dbo].[tbl_olap_fact] 
    ([transaction_id], 
    [status_id], 
    [staus_name], 
    [date_dim]) 
(
  SELECT DISTINCT
    core.id          as 'transaction_id',
    core_status.ID   as 'status_id',
    core_status.name as 'status_name',
    CAST(YEAR(core.VersionDate) as VARCHAR(4)) + 
    RIGHT('00' + CAST(MONTH(core.VersionDate) as VARCHAR(2)) ,2) +
    RIGHT('00' + CAST(DAY(core.VersionDate)   as VARCHAR(2)), 2) as 'date_dim' 
  FROM 
    [dbo].[tbl_application] as core
        inner join tbl_applicationstatus as core_status
         on core.ApplicationStatusID = core_status.ID
  WHERE IsRaw = 0
);

作为 OLAP 服务器,我使用的是 Mondrian。定义多维数据库逻辑模型的蒙德里安模式:

<Schema name="olap_schema">
  <Dimension type="TimeDimension" visible="true" highCardinality="false" name="Date first dim">
    <Hierarchy name="date_hierarchy" visible="true" hasAll="true" primaryKey="date_key" description="">

      <Table name="tbl_date_dim" schema="dbo">
      </Table>

      <Level name="" 
            visible="true" 
            table="tbl_date_dim" 
            column="Year" 
            nameColumn="Year" 
            type="Numeric" 
            uniqueMembers="true" 
            levelType="TimeYears" 
            hideMemberIf="Never" 
            description="">         
      </Level>

      <Level name="" 
             visible="true" 
             table="tbl_date_dim" 
             column="Month" 
             nameColumn="Month" 
             ordinalColumn="Month" 
             type="Numeric" 
             uniqueMembers="false" 
             levelType="TimeMonths" 
             hideMemberIf="Never" 
             description="">
      </Level>

      <Level name="" 
             visible="true" 
             table="tbl_date_dim" 
             column="Day" 
             nameColumn="Day" 
             ordinalColumn="Day" 
             type="Numeric" 
             uniqueMembers="false" 
             levelType="TimeDays" 
             hideMemberIf="Never" 
             description="">
      </Level>

    </Hierarchy>
  </Dimension>

  <Dimension type="TimeDimension" visible="true" highCardinality="false" name="Date second dim">
    <Hierarchy name="date_hierarchy" visible="true" hasAll="true" primaryKey="date_key" description="">
      <Table name="tbl_date_dim" schema="dbo">
      </Table>

      <Level name="" 
             visible="true" 
             table="tbl_date_dim" 
             column="Year" 
             nameColumn="Year" 
             type="Numeric" 
             uniqueMembers="true" 
             levelType="TimeYears" 
             hideMemberIf="Never" 
             description="">
      </Level>

      <Level name="" 
             visible="true" 
             table="tbl_date_dim" 
             column="Month" 
             nameColumn="Month" 
             ordinalColumn="Month" 
             type="Numeric" 
             uniqueMembers="false" 
             levelType="TimeMonths" 
             hideMemberIf="Never" 
             description="">
      </Level>

      <Level name="" 
             visible="true" 
             table="tbl_date_dim" 
             column="Day" 
             nameColumn="Day" 
             ordinalColumn="Day" 
             type="Numeric" 
             uniqueMembers="false" 
             levelType="TimeDays" 
             hideMemberIf="Never" 
             description="">
      </Level>

    </Hierarchy>
  </Dimension>

  <Dimension type="StandardDimension" visible="true" highCardinality="false" name="Status dimension">
    <Hierarchy name="status_hierarchy" visible="true" hasAll="true" primaryKey="ID" description="">
      <Table name="tbl_applicationstatus" schema="dbo">
      </Table>
      <Level name="" 
             visible="true" 
             table="tbl_applicationstatus" 
             column="Name" 
             nameColumn="Name" 
             type="String" 
             uniqueMembers="true" 
             levelType="Regular" 
             hideMemberIf="Never" 
             description="">
      </Level>
    </Hierarchy>
  </Dimension>

  <Cube name="enrollment_cube" caption="" visible="true" description="" cache="true" enabled="true">
    <Table name="tbl_olap_fact" schema="dbo">
    </Table>

    <DimensionUsage source="Date first dim" name="X axis" caption="" visible="true" foreignKey="date_dim" highCardinality="false">
    </DimensionUsage>

    <DimensionUsage source="Date second dim" name="Y axis" caption="" visible="true" foreignKey="date_dim" highCardinality="false">
    </DimensionUsage>

    <DimensionUsage source="Status dimension" name="Z axis" caption="" visible="true" foreignKey="status_id" highCardinality="false">
    </DimensionUsage>

    <Measure name="TotalCount" column="transaction_id" aggregator="count" caption="Total" visible="true">
    </Measure>

  </Cube>

</Schema>

作为 OLAP 客户端,我使用的是 Saiku Analytics。

在此处输入图像描述

基本上,我得到了正确的数据——但不太确定。例如,我用来填充事实表的方式是否正确?我是否正确构建 ETL 流程?这是一种测试模式,我在构建数据仓库和多维模型方面做了一些实验。

4

1 回答 1

0

这里有一个免责声明:我从未使用过蒙德里安,我在这里给出的建议是通用的,坚持接近 Kimball 的做事方式。如果蒙德里安需要对模式进行一些特定的更改,那就去做吧。


tbl_date_dim

这是一个好的开始 - 日期维度至关重要。您可能会发现您还需要一个单独的时间维度(例如,如果您想按小时查看事物)。

我会这样做是删除 ID 列。它的用途是什么?每个 YYYYMMDD 值都是唯一的,这里的标准模式是简单地将其用作该表的代理键。

您可能会发现您还想在此表中添加更多列;现在,我建议添加一个包含实际日期的日期列,因为这是该维度的业务关键。您应该始终在每个维度中同时拥有代理键​​和业务键。

如果您还不熟悉这个术语,请阅读业务键的概念 - 它基本上是一个有意义的名称,您的组织在引用特定维度成员时会使用它,通常是某种名称。人们经常犯错误,使用源系统中无意义的代码或无用的缩写,但这些确实应该避免。

我建议以不同的方式填充 tbl_date_dim。当然,你现在的做法是可行的,但你的日期维度最终会被许多其他表格引用,你可能会发现它缺少你需要的日期。标准解决方案只是编写脚本,甚至将电子表格放在一起并导入,并在过去和未来包含合适的日期范围。它从来没有那么大,所以尺寸并不是真正的问题。如果您想编写脚本,您应该能够通过一些搜索找到为您完成工作的脚本。

tbl_applicationstatus

由于您没有显示 DDL,因此很难对此发表评论。不过,您很可能不应该使用整个源表。确保在数据仓库中创建了代理键(标识列很好,将其命名为 application_status_key)和业务键。这可能是 status_name。

tbl_olap_fact

事实表应该是相同粒度的一个或多个度量,以及维度表的外键。理解颗粒是至关重要的,你应该考虑颗粒是什么,然后给这个事实起一个有意义的名字来反映它。例如,如果您的事实将具有与交易相关的更多度量之一,那么 tbl_transaction_fact 可能是一个好名字。

有点不清楚您要在这里测量什么,因为您没有解释 tbl_application 源表中的数据是什么,但看起来您可能正在尝试计算某个应用程序状态时执行的事务数放?请注意,您实际上没有任何附加措施;加法度量是可以相加的东西 - 货币数量,项目数量等。

如果您只是将其作为示例,我强烈建议您首先考虑一个您希望您的立方体回答的问题,该问题涉及一些附加的东西(即类似于“1 月份创建的所有应用程序值多少钱?” 如果您的应用程序具有货币价值),然后建模一些可以回答该问题的东西。

您也完全可以进行计数,但可能不需要导入源的 transaction_id 值 - 您可以只计算您的 ID 列。

您应该从事实表中删除 status_name,因为您应该通过链接到您的状态维度并使用那里的名称列来实现。状态名称是该维度的业务键,而不是非附加度量。

当您填充事实时,通常的模式是使用业务键,然后从维度本身或查找表中获取代理键,然后仅使用指向的代理键加载事实方面。


有一个非常方便的 Kimball 指南,它简要概述了各种技术。它既可以作为查找概念的初始位置,也可以在需要提醒时参考——我建议通读并保存它。

于 2016-08-16T16:12:34.393 回答