web-dev-qa-db-ja.com

SQL Server 2016のシステムバージョンのテンポラルテーブルを使用した、ゆっくりと変化するディメンションのクエリ戦略

システムバージョンのテンポラルテーブル (SQL Server 2016の新機能)を使用する場合、この機能を使用して大規模なリレーショナルデータウェアハウスで緩やかに変化するディメンションを処理する場合、クエリの作成とパフォーマンスにどのような影響がありますか?

たとえば、100,000行のCustomerディメンションとPostal Code列と、Sales外部キー列を持つ数十億行のCustomerIDファクトテーブル。また、「顧客の郵便番号別の2014年の売上合計」をクエリするとします。簡略化されたDDLは次のとおりです(明確にするために多くの列を省略しています)。

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

興味深いのは、顧客が1年間に引っ越してきたため、同じ顧客が異なる郵便番号を持っている可能性があることです。また、顧客が離れてから戻った可能性もあります。つまり、同じ顧客に対して、同じ郵便番号を持つ複数の履歴レコードが存在する可能性があります。 「郵便番号別売上高」に対する私のクエリは、顧客の郵便番号が時間とともにどのように変化するかに関係なく、正しい結果を計算できるはずです。

テンポラルテーブルを使用して顧客ディメンションのみをクエリする方法を理解しています(例:SELECT * FROM Customer FOR SYSTEM_TIME FROM '2014-1-1' TO '2015-1-1')しかし、ファクトテーブルに最も正確かつ効率的に結合する方法がわかりません。

これはどのようにクエリする必要がありますか?

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

そして、このようなクエリを作成するときに注意すべきパフォーマンスの考慮事項は何ですか?

17
Justin Grant

あなたの場合、顧客ごとの郵便番号のミューテーションのクエリ数を分離するために、派生テーブルが必要だと思います。

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:クエリはDWH /分析シナリオを提供することになっているため、列ストアインデックスはチェックするオプションです。私も 以前にいくつかのベンチマークを作成しました 1000万行のテーブル。

1
Alexandr Volok