我有一个大的事实表和一个简单星型模式中的小得多的维度表:
--1.
CREATE TABLE dbo.Dim
(
Id INT NOT NULL IDENTITY PRIMARY KEY CLUSTERED,
CustomerName VARCHAR(2000)
)
--index
CREATE UNIQUE NONCLUSTERED INDEX uniqueindex1 ON Dim(CustomerName);
--2.
CREATE TABLE dbo.Fact
(
...
PurchaseDate DATE
CustomerNameId INT CONSTRAINT fk1 FOREIGN KEY (CustomerNameId) REFERENCES dbo.Dim(Id)
...
)
--index
CREATE CLUSTERED COLUMNSTORE INDEX ccs ON dbo.Fact;
运行以下简单查询,过滤事实表并加入维度:
SELECT sd.CustomerName,f.*
FROM dbo.Fact f
INNER JOIN dbo.Dim sd ON sd.Id = f.CustomerNameId
WHERE f.PurchaseDate IN (
'20000506',
'20000507',
'20000508',
'20000509',
'20000501',
'20000502',
'20000503'
)
有趣的是,维度表倾向于在 4 次迭代中扫描所有 500 000 行,但最终在事实表的该日期范围内只需要几千行。
这对于较大的维度表来说是非常低效的,基本上所有的行都是一直扫描的,就像查找表索引甚至不存在一样。
预期的事情是sql server首先将事实表限制在日期范围内,然后使用这个有限的CustomerKeyId范围,它使用索引查找从小维度表中查找CustomerName。
- 这真的是星型模式的效率低下,还是我在这里想念什么?
- 换句话说,我怎么能强制 sql server 准备有限的 CustomerKeyId 表并只查找那些?(不知何故有CTE?)
这是一个可以玩的示例:
计划在这里。
您会看到使用索引查找的循环连接比扫描并行执行的每个线程上的维度并执行哈希连接更昂贵: