Ao usar uma tabela temporal com versão do sistema (nova no SQL Server 2016), quais são as implicações de autoria e desempenho da consulta quando esse recurso é usado para lidar com dimensões de alteração lenta em um grande armazém de dados relacionais?
Por exemplo, suponha que eu tenha uma Customer
dimensão de 100.000 linhas com uma Postal Code
coluna e uma Sales
tabela de fatos com vários bilhões de linhas com uma CustomerID
coluna de chave estrangeira. E suponha que eu queira consultar "Total de vendas em 2014 por código postal do cliente". O DDL simplificado é assim (omitindo muitas colunas para maior clareza):
CREATE TABLE Customer
(
CustomerID int identity (1,1) NOT NULL PRIMARY KEY CLUSTERED,
PostalCode varchar(50) NOT NULL,
SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL,
SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON);
CREATE TABLE Sale
(
SaleId int identity(1,1) NOT NULL PRIMARY KEY CLUSTERED,
SaleDateTime datetime2 NOT NULL,
CustomerId int NOT NULL FOREIGN KEY REFERENCES Customer(CustomerID),
SaleAmount decimal(10,2) NOT NULL
);
O que interessa é que os clientes podem ter se mudado durante o ano e, portanto, o mesmo cliente pode ter códigos postais diferentes. E é até remotamente possível que um cliente se afaste e depois volte, o que significa que pode haver vários registros de histórico para o mesmo cliente com o mesmo código postal! Minha consulta de "vendas por código postal" deve poder calcular resultados corretos, independentemente de como os códigos postais dos clientes mudam com o tempo.
Entendo como usar tabelas temporais para consultar apenas a dimensão do cliente (por exemplo SELECT * FROM Customer FOR SYSTEM_TIME FROM '2014-1-1' TO '2015-1-1'
), mas não sei como ingressar com mais precisão e eficiência na tabela de fatos.
É assim que eu devo consultá-lo?
SELECT c.PostalCode, sum(s.SaleAmount) SaleAmount
FROM Customer c FOR SYSTEM_TIME FROM '2014-1-1' TO '2015-1-1'
JOIN Sale s ON s.CustomerId = c.CustomerId
WHERE s.SaleDateTime >= '2014-1-1' AND s.SaleDateTime < '2015-1-1'
AND c.SysStartTime >= s.SaleDateTime
AND c.SysEndTime < s.SaleDateTime
GROUP BY c.PostalCode
E quais são as considerações de desempenho que devo observar ao fazer consultas como essa?