Strategie di query che utilizzano tabelle temporali con versione di sistema di SQL Server 2016 per dimensioni a modifica lenta


17

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 Customerdimensione di 100.000 righe con una Postal Codecolonna e una Salestabella dei fatti multi-miliardaria con una CustomerIDcolonna 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?

Risposte:


1

Penso che nel tuo caso sia necessaria una tabella derivata per isolare il numero di mutazioni dei codici postali per cliente:

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: poiché la query dovrebbe servire scenari DWH / Analytics, l'indicizzazione columnstore è un'opzione da verificare. Ho anche fatto alcuni benchmark in precedenza per una tabella di 10 milioni di righe.


Perché è necessario contare il numero di modifiche per cliente? I clienti che modificano il codice postale nel corso dell'anno aggiungono complessità alla query, ma in realtà non sembra essere necessario segnalare tali cambiamenti.
Justin Grant,

@JustinGrant Numero di modifiche per mostrare come queste mutazioni possono essere recuperate dai dati storici. Tuttavia, queste righe sono state aggiunte ieri: 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. Rendi la richiesta più chiara. In tal caso, SYSTEM_TIME dovrebbe essere impostato allo stesso modo per entrambe le tabelle. e ci sono due modi: 1) Utilizzare le tabelle private e applicare system_time per entrambe le tabelle. 2) O semplicemente creare una vista che contiene un join e applicare SYSTEM_TIME durante l'interrogazione della vista
Alexandr Volok,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.