数据仓库设计:组合的日期时间维度与单独的日期和时间维度和时区


10

我们刚刚开始为新的数据仓库设计,我们正在尝试设计日期和时间维度的工作方式。我们需要能够支持多个时区(可能至少是GMT,IST,PST和EST)。最初,我们以为我们可以将日期时间维度的组合范围缩小到15分钟左右,这样一来,事实表中就有一个键,而所有受支持时区的所有不同日期时间数据都在一个维度表中。(即日期键,GMT日期,GMT时间,IST日期,IST时间等)

Kimball建议将日期维度与日期时间维度分开,以防止表格过大(数据仓库工具包第240页),听起来不错,但这意味着我们在每个时区的事实表中都有两个键我们需要支持(一个代表日期,另一个代表一天中的时间)。

由于我在这方面经验不足,所以我希望有人知道两种方法之间的权衡,即性能与所有不同时区密钥的管理。也许还有其他方法,我已经看到有人谈论每个时区在事实表中有单独的行,但是如果您的事实表有数百万行,那么您需要将其四倍以添加时区,这似乎是一个问题。

如果我们进行15分钟的粒化,那么我们的日期时间维度表中每年将有131,400(24 * 15 * 365)行,这听起来听起来并不可怕,但是直到我们测试了一些之后,我们才能确定原型查询。在事实表中具有单独的时区键的另一个问题是查询必须根据所需的时区将维度表连接到其他列,也许这是SSAS为您解决的事情,我不确定。

感谢您的任何想法,-Matt


1
这个问题也存在于Stack Overflow中:stackoverflow.com/questions/2507289/…
所有行业的乔恩2014年

Answers:


5

将日期和时间分开可以让您轻松地按时间进行汇总。例如:如果您要运行查询以查找一天中的哪个时段最忙。使用单独的时间维度很容易执行此操作。

另外,您应该只有一个时间键。确定GMT / EST时间-然后在事实表中使用该时间。如果您需要根据其他时区运行报告,只需在应用程序或查询中将其转换即可。


好的,这是有道理的,用户不能再根据其时区对数据进行分组,但是为了简化设计,这可能是我们可以接受的。
Matt Palmerlee 2011年

@MattPalmerlee:如果您给用户,可以按时区分组。我通常将其包括在Geography表中,但是如果不适用,则可以将其添加为事实表的属性。
所有行业的乔恩2014年

5

只是我们决定如何实现DataWarehouse以支持多个时区并尽可能高效的后续措施:我们选择创建时区表(ID,名称等...)以及“时区”桥”表如下所示:

time_zone_bridge
---------------
date_key_utc
time_key_utc
timezone_id
date_key_local
time_key_local

这样,我们可以使正常的日期和时间维度表保持较小,所有事实都链接到UTC日期/时间键,然后,如果我们需要按其他时区进行报告/分组,我们只需要通过时区桥表进行联接并将本地日期/时间键链接回日期和时间维度表。我们使用从SSIS调用的C#代码填充时区桥接表,因为它比直接从SqlServer进行TZ处理要简单得多。


我还认为您的解决方案可能是最有意义的,而无需太复杂。我正在使用类似于您的timeZone表和TimeZoneBridge测试我的DW。它还具有TimeDimension和DateDimension表。我在date_key_local,time_key_local和timezone_id上​​创建了聚簇索引,因此使用TimeZoneBridge将本地时间转换为UTC时间将很快。
dsum 2012年

1
我们用于桥接表的主要集群键位于utc日期/时间列+时区ID(如果我没记错的话),因为所有事实表的时间键都位于utc中,因此您将通过utc加入到桥接中键+ tz ID,将聚集索引放在这些键上可能会更好。尽一切可能满足您的需求。我很高兴我的回答对某人有所帮助,我认为这是一个很好的方法,并且从我们所有的测试来看,它仍然相当快,请谨慎对待WHERE子句:尽早过滤掉您想要的日期范围在您的查询中可能。
马特·帕默里

仅包含整个日期吗?或者,如果事实表中有86000个“日期/时间键”值,那么桥接表将具有86000行* n个受支持的时区,仅此一天?
亚伦·伯特兰

1
也许您可以添加确切的表定义,以便读者可以看到主要的唯一约束。
ypercubeᵀᴹ

@AaronBertrand取决于要跟踪数据的粒度(或您选择的粒度),在我们的情况下,我们只需要在事实表中保留15分钟的粒度,因此我们要支持的每个时区每天只有4 * 24 = 96条记录,这是完全合理的。
马特·帕默里

2

我已经看到DateTime拒绝使用合并尺寸的仓库的想法,但是我还没有看到真正清楚的原因。稍微简化一下,这是我现在正在构建的事实表:

Transactions
(
...
CreatedDateTimeSK         INT NOT NULL,  -- Four bytes per date...
AuthorizedDateTimeSK      INT NOT NULL,
BatchSubmittedDateTimeSK  INT NOT NULL,
BatchApprovedDateTimeSK   INT NOT NULL,
SettlementDateTimeSK      INT NOT NULL,
LocalTimeZoneSK           TINYINT NOT NULL  -- ...plus one byte for the time zone
)

这些DateTime字段连接到DateTime表:

DateTimes
(
DateTimeSK   INT NOT NULL PRIMARY KEY,
SQLDate      DATE NOT NULL,
SQLDateTime  DATETIME2(0) NOT NULL,
Year         SMALLINT NOT NULL,
Month        TINYINT NOT NULL,
Day          TINYINT NOT NULL,
Hour         TINYINT NOT NULL,
Minute       TINYINT NOT NULL CHECK (Minute IN (0, 30)),
...
)

这是半小时的分辨率,因此每天有48条记录,在20年中为350,400条-相当可管理。

事件日期/时间在存储时会转换为UTC,但是通过LocalTimeZoneSK字段和桥表,我们可以轻松地加入以获取本地时间:

TimeZoneBridge
(
DateTimeSK       INT NOT NULL,
TimeZoneSK       TINYINT NOT NULL,
PRIMARY KEY (DateTimeSK, TimeZoneSK),
LocalDateTimeSK  INT NOT NULL
)

要获取今天创建的交易,UTC时间:

SELECT COUNT(*)
FROM Transactions AS T
  INNER JOIN DateTimes AS CD ON T.CreatedDateTimeSK = CD.DateTimeSK
WHERE CD.SQLDate = '2014-08-22'

要获取今天创建的交易,请在当地时间进行交易:

SELECT COUNT(*)
FROM Transactions AS T
  INNER JOIN TimeZoneBridge AS TZB ON T.CreatedDateTimeSK = TZB.DateTimeSK AND T.TimeZoneSK = TZB.TimeZoneSK
  INNER JOIN DateTimes AS CD ON TZB.LocalDateTimeSK = CD.DateTimeSK
WHERE CD.SQLDate = '2014-08-22'

您可以通过更换被诱惑把事情简单化TimeZoneSKREAL偏移(例如,-5.0美国中部夏令时间),但这将打破,如果是事实记录一些日期/时间是夏令时,有些则不是。

如果事实记录的事件可以发生在不同的时区,例如货运或航班,则每个日期都需要一个时区字段,并且每个日期最多五个字节。


这是一种创造性的方法。但是,正如您所说的,合并的日期时间暗表中只有350,400行,如果您开始将粒度更改为更高分辨率,您将迅速获得数百万条记录。如果选择将日期维与时间维分开,则时间维表中仅包含48行,日期维表中每年仅365行(或20年中的7300行)。然后,事实表仅包含date_key和time_key的列。如果您有一些只需要日期粒度的事实表,这也将使其更加灵活。
马特·帕默里

1
一个维度中的一百万行与我无关-数据仅十年更改一次,并且PK和两个或三个最常用字段上的覆盖索引将占用很少的服务器RAM。但是,SMALLINT在10亿行的事实表中添加半秒是12 GB加上开销,现在您正在谈论真钱。对于只需要存储日期的日期,您当然可以将它们指向相应日期的“ 12:00 AM”记录。
所有行业的乔恩2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.