Quando si utilizza una tabella temporale con versione del sistema (nuova in SQL Server 2016), quali sono le implicazioni sulla creazione e sulle prestazioni della query quando questa funzionalità viene utilizzata per gestire le dimensioni a modifica lenta in un grande data warehouse relazionale?
Ad esempio, supponiamo che io abbia una Customer
dimensione di 100.000 righe con una Postal Code
colonna e una Sales
tabella dei fatti multi-miliardaria con una CustomerID
colonna chiave esterna. E suppongo di voler interrogare "Vendite totali 2014 per codice postale del cliente". Il DDL semplificato è così (omettendo molte colonne per chiarezza):
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
);
Dove diventa interessante è che i clienti potrebbero essersi spostati durante l'anno, quindi lo stesso cliente potrebbe avere codici postali diversi. Ed è anche possibile che un cliente si sia allontanato e poi sia tornato indietro, il che significa che potrebbero esserci più record di cronologia per lo stesso cliente con lo stesso codice postale! La mia richiesta di "vendite per codice postale" dovrebbe essere in grado di calcolare i risultati corretti indipendentemente da come i codici postali dei clienti cambiano nel tempo.
Capisco come utilizzare le tabelle temporali per interrogare la dimensione del cliente da sola (ad es. SELECT * FROM Customer FOR SYSTEM_TIME FROM '2014-1-1' TO '2015-1-1'
) Ma non sono sicuro di come aderire in modo più preciso ed efficiente alla tabella dei fatti.
È così che dovrei interrogarlo?
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 quali sono le considerazioni sulle prestazioni che dovrei fare attenzione quando faccio domande come questa?