緩やかに変化するディメンションに対してSQL Server 2016システムバージョンのテンポラルテーブルを使用したクエリ戦略


17

使用している場合、システムバージョン管理一時テーブル(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
);

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

テンポラルテーブルを使用して顧客ディメンション(たとえば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

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

回答:


1

あなたの場合、顧客ごとに郵便番号の突然変異のクエリ数を分離するために派生テーブルが必要だと思います:

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 / Analyticsシナリオを提供することになっているため、列ストアインデックスはチェックするオプションです。また、以前に1,000万行のテーブルのベンチマークを作成しました。


顧客ごとに変更の数を数える必要があるのはなぜですか?1年の間に郵便番号を変更する顧客はクエリに複雑さを追加しますが、実際にはそれらの変更について報告する必要はないようです。
ジャスティングラント

@JustinGrant変更の数は、履歴データからこれらの突然変異を取得する方法を示すことです。ただし、昨日追加したこれらの行:「郵便番号による販売」のクエリは、顧客の郵便番号の経時変化に関係なく、正しい結果を計算できるはずです。リクエストをより明確にします。その場合、SYSTEM_TIMEは両方のテーブルに対して同じ方法で設定する必要があります。2つの方法があります。1)権限のないテーブルを使用し、両方のテーブルにsystem_timeを適用します。2)または、結合を保持するビューを作成し、ビューのクエリにSYSTEM_TIMEを適用する
Alexandr Volok
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.