Lorsque vous utilisez une table temporelle versionnée par le système (nouvelle dans SQL Server 2016), quelles sont les implications en matière de création de requêtes et de performances lorsque cette fonctionnalité est utilisée pour gérer les dimensions à évolution lente dans un grand entrepôt de données relationnelles?
Par exemple, supposons que j'ai une Customer
dimension de 100 000 lignes avec une Postal Code
colonne et une Sales
table de faits de plusieurs milliards de lignes avec une CustomerID
colonne de clé étrangère. Et supposons que je souhaite interroger "Total des ventes 2014 par code postal du client". Le DDL simplifié est comme ceci (en omettant de nombreuses colonnes pour plus de clarté):
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
);
Ce qui devient intéressant, c'est que les clients peuvent avoir déménagé au cours de l'année, de sorte que le même client peut avoir des codes postaux différents. Et il est même possible à distance qu'un client s'éloigne puis recule, ce qui signifie qu'il pourrait y avoir plusieurs enregistrements d'historique pour le même client avec le même code postal! Ma requête de "ventes par code postal" devrait être en mesure de calculer des résultats corrects quelle que soit l'évolution des codes postaux des clients au fil du temps.
Je comprends comment utiliser des tables temporelles pour interroger la dimension client seule (par exemple SELECT * FROM Customer FOR SYSTEM_TIME FROM '2014-1-1' TO '2015-1-1'
), mais je ne sais pas comment joindre le plus précisément et efficacement la table de faits.
Est-ce ainsi que je devrais l'interroger?
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
Et quelles sont les considérations de performances que je dois surveiller lorsque je fais des requêtes comme celle-ci?