Stratégies de requête à l'aide de tables temporelles avec version système SQL Server 2016 pour des dimensions à évolution lente


17

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 Customerdimension de 100 000 lignes avec une Postal Codecolonne et une Salestable de faits de plusieurs milliards de lignes avec une CustomerIDcolonne 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?

Réponses:


1

Je pense que, dans votre cas, une table dérivée est nécessaire pour isoler le nombre de requêtes de mutations de codes postaux par client:

SELECT c.postalcode 
, sum(s.SaleAmount) SaleAmount
, count(postcode_mutations.customerid) as CntCustomerChangedPostCode   
FROM dbo.Sale s
JOIN dbo.Customer c on s.customerid = c.customerid

LEFT JOIN (
SELECT 
    CustomerID
FROM [dbo].[Customer]
FOR SYSTEM_TIME FROM '20140101' TO '20150101'
GROUP BY CustomerID
HAVING COUNT(DISTINCT PostalCode) > 1
) postcode_mutations on s.customerid = postcode_mutations.customerid

WHERE s.SaleDateTime >= '2014-1-1' AND s.SaleDateTime < '2015-1-1'
GROUP BY c.PostalCode

upd: Étant donné que la requête est censée servir des scénarios DWH / Analytics, l'indexation columnstore est une option à vérifier. J'ai également fait quelques repères précédemment pour une table de 10 millions de lignes.


Pourquoi faut-il compter le nombre de changements par client? Les clients qui changent de code postal au cours de l'année ajoutent de la complexité à la requête, mais il ne semble pas nécessaire de faire rapport sur ces changements.
Justin Grant

@JustinGrant Le nombre de changements consiste à montrer comment ces mutations peuvent être récupérées à partir des données historiques. Cependant, ces lignes, vous avez ajouté hier: Ma requête de "ventes par code postal" devrait être capable de calculer des résultats corrects quelle que soit l'évolution des codes postaux des clients au fil du temps. Rendre la demande plus claire. Dans ce cas, SYSTEM_TIME doit être défini de la même manière pour les deux tables. et il y a deux manières: 1) Utiliser des tables privées et appliquer system_time pour les deux tables. 2) Ou créez simplement une vue contenant une jointure et appliquez SYSTEM_TIME lors de l'interrogation de la vue
Alexandr Volok
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.