Design do Datawarehouse: dimensão Data / hora combinada vs. dimensões e fusos horários separados de dia e hora

10

Estamos apenas começando o design de um novo data warehouse e estamos tentando projetar como nossas dimensões de data e hora funcionarão. Precisamos oferecer suporte a vários fusos horários (provavelmente pelo menos GMT, IST, PST e EST). Inicialmente, pensávamos que teríamos uma dimensão de data e hora combinada ampla, talvez com granularidade de 15 minutos, dessa forma, teríamos uma chave em nossas tabelas de fatos e todos os diferentes dados de data e hora para todos os fusos horários suportados estarão em uma tabela de dimensão. (ou seja, chave de data, data GMT, hora GMT, data IST, hora IST, etc ...)

Kimball sugere ter uma dimensão de dia separada da dimensão da hora do dia para impedir que a tabela fique muito grande (O kit de ferramentas do armazém de dados p. 240), o que parece bom, no entanto, isso significa que temos duas chaves em nossas tabelas de fatos para cada fuso horário precisamos apoiar (um para a data e outro para a hora do dia).

Como eu sou muito inexperiente nessa área, espero que alguém conheça as vantagens e desvantagens entre as duas abordagens, ou seja, desempenho versus gerenciamento de todas as chaves de fuso horário diferentes. Talvez também existam outras abordagens. Vi algumas pessoas falando sobre ter uma linha separada na tabela de fatos por fuso horário, mas isso parece um problema se as tabelas de fatos são milhões de linhas, você precisa quadruplicá-lo para adicionar fusos horários .

Se fizermos a granulação de 15 minutos, teremos 131.400 (24 * 15 * 365) linhas por ano em nossa tabela de dimensões de data e hora que não parece muito ruim para o desempenho, mas não teremos certeza até testarmos alguns consultas de protótipo. A outra preocupação em ter chaves de fuso horário separadas na tabela de fatos é que a consulta precisa associar a tabela de dimensões a uma coluna diferente com base no fuso horário desejado, talvez seja algo que o SSAS cuide de você, não tenho certeza .

obrigado por quaisquer pensamentos, -Matt

Matt Palmerlee
fonte
11
Essa pergunta também existe no estouro de pilha: stackoverflow.com/questions/2507289/… .
Jon of All Trades

Respostas:

5

Separar a data e a hora permitirá que você faça agregações por hora com muita facilidade. por exemplo: se você deseja executar uma consulta para descobrir qual período do dia está mais ocupado. Isso é facilmente realizado usando uma dimensão de tempo separada.

Além disso, você deve ter apenas uma tecla do tempo. Decida o horário GMT / EST - use-o na tabela de fatos. Se você precisar executar relatórios com base no outro fuso horário, basta convertê-lo em seu aplicativo ou consulta.

Dharmendar Kumar 'DK'
fonte
Ok, isso faz sentido, os usuários não podem agrupar os dados com base no fuso horário, mas isso provavelmente é algo que poderíamos viver sem para simplificar o design.
Matt Palmerlee
@MattPalmerlee: Os usuários podem agrupar por fuso horário, se você der a eles. Normalmente, eu o incluiria na Geographytabela, mas se não houver nenhum, você poderá adicioná-lo como um atributo da sua tabela de fatos.
Jon of All Trades
5

Apenas um acompanhamento de como decidimos implementar nosso DataWarehouse para oferecer suporte a vários fusos horários e ser o mais eficiente possível: optamos por criar uma tabela de fusos horários (ID, nome, etc ...) e também um "Fuso horário ponte "que fica assim:

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

Dessa forma, podemos manter pequenas as tabelas de dimensões de data e hora normais, todos os nossos fatos vinculam-se às chaves de data / hora do UTC. Se precisarmos relatar / agrupar por um fuso horário diferente, basta entrar na tabela de ponte de fuso horário e vincule as chaves locais de data / hora de volta às tabelas de dimensões de data e hora. Nós preenchemos nossa tabela de ponte de fuso horário usando o código C # invocado no SSIS, pois isso era muito menos complicado do que fazer coisas TZ diretamente do SqlServer.

Matt Palmerlee
fonte
Também acho que sua solução provavelmente faz mais sentido sem entrar em algo muito complicado. Estou testando meu DW usando uma tabela timeZone e TimeZoneBridge semelhantes ao seu. Ele também possui as tabelas TimeDimension e DateDimension. Criei um índice clusterizado em date_key_local, time_key_local e timezone_id, para que a conversão da hora local para a hora UTC usando o TimeZoneBridge fosse rápida.
DSoma
11
Nossa chave de cluster principal para a tabela de bridge está nas colunas utc date / time + o ID do fuso horário (se bem me lembro), já que todas as chaves de tempo das tabelas de fatos estarão em utc, você ingressará na bridge através do utc chaves + tz id, pode funcionar melhor ter o índice agrupado nessas. Faça o que faz sentido para as suas necessidades. Fico feliz que minha resposta tenha ajudado alguém, acho que é uma boa abordagem e, de todos os nossos testes, ainda é razoavelmente rápido, apenas tome cuidado quando se trata da cláusula WHERE: filtre os intervalos de datas que você deseja assim que possível possível em suas consultas.
Matt Palmerlee
Isso contém apenas datas inteiras? Ou se você tiver 86000 valores de "chave de data / hora" em sua tabela de fatos, a tabela de ponte terá 86000 linhas * n fusos horários suportados, e isso é apenas para esse dia?
Aaron Bertrand
11
talvez você possa adicionar a definição exata da tabela que possui, para que os leitores possam ver as principais restrições exclusivas.
ypercubeᵀᴹ
@AaronBertrand, depende do granulo (ou granularidade que você escolher) para rastrear seus dados. No nosso caso, precisávamos de granularidade de apenas 15 minutos em nossas tabelas de fatos, portanto, são apenas 4 * 24 = 96 registros por dia por fuso horário que desejamos oferecer suporte, o que é completamente razoável.
Matt Palmerlee
2

Vi a ideia de um armazém usando uma DateTimedimensão combinada rejeitada, mas não vi uma razão muito clara para isso. Simplificando um pouco, aqui está a tabela de fatos que estou construindo agora:

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
)

Os DateTimecampos se juntam a uma tabela 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)),
...
)

Como a resolução é de meia hora, há 48 registros por dia, 350.400 em 20 anos - bastante administráveis.

A data / hora do evento são convertidas para UTC quando armazenadas, mas com o LocalTimeZoneSKcampo e uma tabela de ponte, podemos ingressar facilmente para obter a hora local:

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

Para obter transações criadas hoje, hora UTC:

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

Para obter transações criadas hoje, no horário local da transação:

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'

Você pode ficar tentado a simplificar as coisas, substituindo-o TimeZoneSKpor um REALdeslocamento (por exemplo, -5,0 para o horário de verão central dos EUA), mas isso será interrompido se algumas datas / horas de um registro de fatos estiverem no horário de verão e outras não.

Se os eventos para um registro de fatos puderem ocorrer em fusos horários diferentes, como uma remessa ou um voo, você precisará de um campo de fuso horário para cada data e terá até cinco bytes por data.

Jon de todos os comércios
fonte
É uma abordagem criativa. No entanto, como você diz que terá apenas 350.400 linhas em sua tabela reduzida de data e hora combinada, se você começar a alterar a granulação para uma resolução mais fina, entrará rapidamente nos milhões de registros. Se você optar por ter uma dimensão de data separada da dimensão de tempo, você terá apenas 48 linhas em sua tabela de dimensões de tempo e apenas 365 linhas por ano em sua tabela de dimensões de data (ou 7300 linhas em 20 anos). Sua tabela de fatos simplesmente possui uma coluna para date_key e time_key. Isso também o torna mais flexível se você tiver algumas tabelas de fatos que exigem apenas granularidade de data.
precisa saber é o seguinte
11
Um milhão de linhas em uma dimensão não me interessa - os dados são alterados apenas uma vez por década, e um índice de cobertura no PK e em dois ou três campos mais usados ​​ocupará uma quantidade trivial de RAM do servidor. No entanto, adicionar meia dúzia de SMALLINTs a uma tabela de fatos de bilhões de linhas tem 12 GB mais despesas gerais, e agora você está falando com dinheiro real. Para datas que precisam apenas armazenar a data, é claro que você pode apontá-las para o registro "12:00" para a data apropriada.
Jon of All Trades