Jus*_*ant 17 data-warehouse sql-server slowly-changing-dimension temporal-tables sql-server-2016
当使用系统版本控制的时态表(SQL Server 2016 中的新功能)时,当使用此功能处理大型关系数据仓库中的缓慢变化维度时,查询创作和性能影响是什么?
例如,假设我有一个Customer
带有Postal Code
列的 100,000 行维度和一个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
);
Run Code Online (Sandbox Code Playgroud)
有趣的是,客户可能在一年中搬家了,因此同一客户可能有不同的邮政编码。甚至有可能客户搬走然后又搬回来,这意味着同一客户可能有多个历史记录,但邮政编码相同!无论客户的邮政编码如何随时间变化,我对“按邮政编码销售”的查询都应该能够计算出正确的结果。
我了解如何使用时态表单独查询客户维度(例如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
Run Code Online (Sandbox Code Playgroud)
在进行这样的查询时,我应该注意哪些性能注意事项?
小智 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
Run Code Online (Sandbox Code Playgroud)
upd:由于查询应该服务于 DWH/Analytics 场景,因此列存储索引是一个要检查的选项。我之前还对 1000 万行表做了一些基准测试。