为">数据仓库设计物理数据模型时,应集中精力关注各表的定义以及表之间的关系。
在为物理数据模型设计表时,应考虑使用以下指导原则:
为各维度表定义一个主键,确保最细粒度的级别键的惟一性,并在必要时促进引用约束的实现。
避免在事实表上使用主键和惟一索引,在涉及大量维度键时尤为如此。在摄取大量数据时,这些数据库对象会导致性能成本。
将所连接的各维度对之间的引用约束定义为信息型约束,帮助优化器生成有效的访问计划,从而提高查询性能。
使用 NOT NULL 子句来定义一些列。认识到 NULL 值是指示数据库内数据质量问题的一个好的指标,应该在将数据插入数据库之前研究它。
尽可能将外键列定义为 NOT NULL。
对于 DB2 版本 9.7 或更早的版本,应该为各外键定义单独的索引,以提高星形连接查询的性能。
对于 DB2 版本 10.1,应定义拥有多个外键列的复合索引,以提高星形连接查询的性能。这些索引支持优化器利用全新的 zigzag 连接方法。
在适当的时候,可以使用 NOT NULL 子句、基于单一整数列定义维度级别键。这种定义级别键的方法支持高效的连接和分组。对于雪花维度,级别键通常是主键,而该主键通常是一个整数列。
在数据仓库设计中实现标准数据类型,在编译查询计划时为优化器提供更多的选项。举例来说,如果将一个包含数字的 CHAR(10) 列连接到 INTEGER 列,则需要使用强制转换功能。这种连接会导致性能下降,因为优化器可能无法选择恰当的索引或连接方法。例如,在 DB2 版本 9.7 或更早的版本中,优化器无法选择散列连接,可能也无法利用恰当的索引。
定义和选择级别键
级别键就是一个表中的一个列或多个列的组合,它惟一地标识了维度表中的层级级别。层级级别的一个示例就是日期维度中的 DAY、WEEK、MONTH 和 YEAR。另一个示例就是用来存储零售店铺数据的 STORE 维度表的列。更为复杂的级别键示例是同一个 STORE 表中 CITY、STATE 和 COUNTRY 列的组合级别键在数据仓库内的应用极为广泛,用于将维度表连接到事实表,同时支持聚合表和 OLAP 应用程序。良好的级别键设计能够优化数据仓库查询的性能。
级别键可能属于以下类型之一:
根据来源识别数据源内记录的自然键。举例来说,如果 CITY_NAME 列在维度表中拥有惟一值,那么可以将它用作自然键,表示 CITY 维度的级别。
使用代理键作为标识,帮助减小维度较低的表或事实表的大小。大多数情况下,代理键是一个整数列。您也可以对较大的代理键使用 BIGINT 或 DECIMAL 数据类型。例如,STORE_ID 是生成的惟一整数值,用于标识一家店铺。如果使用整数而非大字符串来表示店铺名称或多列的组合(如 STORE_NAME、CITY_NAME 和 STORE_ID),那么所需占用的事实表空间将会更少。
对所有维度级别列使用代理键能够为以下领域提供帮助:
通过降低 I/O 来提高性能。
降低大型事实表中的外键存储要求。
支持缓慢变化的维度 (SCD)。举例来说,CITY_NAME 可能会发生变化,但 CITY_ID 仍保持不变。
如果维度是非规范化的,那么我们倾向于不使用代理键。这个示例展示了创建某些级别上无代理键的 STORE 维度表的语句:
CREATE TABLE STORE_DIMENSION
( STORE_ID INTEGER NOT NULL,
STORE_NAME VARCHAR(30),
CITY_NAME VARCHAR(30),
STATE_NAME VARCHAR(30),
COUNTRY_NAME VARCHAR(30));
STORE 维度能保持正常功能,因为可以将级别键定义为惟一地标识各级别。举例来说,要惟一地标识 CITY 级别,可以这样定义一个键:[COUNTRY_NAME, STATE_NAME, CITY_NAME]。遗憾的是,在表连接或 GROUP BY 子句中,由三个字符列组成的键的执行方式与单一整数列并不相同。
可以考虑为各级别显式定义一个整数键的方法。对于使用 GROUP BY CITY_ID、STATE_ID、COUNTRY_ID 子句的查询(而非使用 GROUP BY CITY_NAME、STATE_NAME 和 COUNTRY_NAME 子句),这种方法也非常适用。下面的示例展示了通过这种方法创建 STORE 维度表的语句:
CREATE TABLE STORE_DIMENSION
( STORE_ID INTEGER NOT NULL,
STORE_NAME VARCHAR(30),
CITY_ID INTEGER,
CITY_NAME VARCHAR(30),
STATE_ID INTEGER,
STATE_NAME VARCHAR(30),
COUNTRY_ID INTEGER,
COUNTRY_NAME VARCHAR(30));
使用 RUNSTATS 命令收集“列组统计信息”,除了 CITY_NAME、STATE_NAME 和 COUNTRY_NAME 列之间的关系之外,还能捕获代理键列之间的统计关系。