Strategi kueri menggunakan tabel temporal versi sistem SQL Server 2016 untuk Dimensi yang Berubah Secara Perlahan

17

Saat menggunakan tabel temporal versi sistem (baru di SQL Server 2016), apa yang dimaksud dengan authoring query dan implikasi kinerja ketika fitur ini digunakan untuk menangani Dimensi Perlahan-lahan Mengubah dalam gudang data relasional yang besar?

Misalnya, anggap saya memiliki Customerdimensi 100.000 baris dengan Postal Codekolom dan Salestabel fakta multi-miliar baris dengan CustomerIDkolom kunci asing. Dan anggap saya ingin meminta "Total penjualan 2014 berdasarkan kode pos pelanggan". DDL yang disederhanakan adalah seperti ini (menghilangkan banyak kolom untuk kejelasan):

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
);

Yang menarik adalah bahwa pelanggan mungkin telah pindah sepanjang tahun sehingga pelanggan yang sama mungkin memiliki kode pos yang berbeda. Dan bahkan sangat mungkin bahwa pelanggan pindah dan kemudian pindah kembali, artinya mungkin ada beberapa catatan riwayat untuk pelanggan yang sama dengan kode pos yang sama! Permintaan saya "penjualan dengan kode pos" harus dapat menghitung hasil yang benar terlepas dari bagaimana kode pos pelanggan berubah dari waktu ke waktu.

Saya mengerti bagaimana menggunakan tabel temporal untuk menanyakan dimensi pelanggan saja (mis. SELECT * FROM Customer FOR SYSTEM_TIME FROM '2014-1-1' TO '2015-1-1') Tapi saya tidak yakin bagaimana cara bergabung dengan tabel fakta secara paling akurat dan efisien.

Apakah ini bagaimana saya harus menanyakannya?

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

Dan apa pertimbangan kinerja yang harus saya perhatikan ketika membuat pertanyaan seperti ini?

Justin Grant
sumber

Jawaban:

1

Saya pikir, dalam kasus Anda, tabel turunan diperlukan untuk mengisolasi jumlah kueri mutasi kode pos per pelanggan:

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: Karena kueri seharusnya melayani skenario DWH / Analytics, pengindeksan kolomstore adalah opsi untuk memeriksa. Saya juga membuat beberapa tolok ukur sebelumnya untuk tabel 10 juta baris.

Alexandr Volok
sumber
Mengapa perlu untuk menghitung jumlah perubahan per pelanggan? Pelanggan yang mengubah kode pos selama tahun itu memang menambah kerumitan pada kueri, tetapi sebenarnya melaporkan perubahan itu tampaknya tidak diperlukan.
Justin Grant
@JustinGrant Jumlah perubahan adalah untuk menunjukkan bagaimana mutasi ini dapat diambil dari data historis. Namun, baris ini, Anda tambahkan kemarin: Permintaan saya "penjualan dengan kode pos" harus dapat menghitung hasil yang benar terlepas dari bagaimana kode pos pelanggan berubah dari waktu ke waktu. Buat permintaan lebih jelas. Dalam hal ini, SYSTEM_TIME harus ditetapkan dengan cara yang sama untuk kedua tabel. dan ada dua cara: 1) Gunakan tabel yang kurang dan menerapkan system_time untuk kedua tabel. 2) Atau cukup buat tampilan yang mengandung join dan terapkan SYSTEM_TIME pada permintaan tampilan
Alexandr Volok