Rom*_*kij 10 sql-server indexed-view sql-server-2012
SQL小提琴:http://sqlfiddle.com/#!6/d4496/1 (为您的实验预先生成数据)
有明显的表:
CREATE TABLE Entity
(
ID int,
Classificator1ID int,
Classificator2ID int,
Classificator3ID int,
Classificator4ID int,
Classificator5ID int
);
Run Code Online (Sandbox Code Playgroud)
和观点:
CREATE VIEW dbo.EntityView (ID, Code1, Code2, Code3, Code4, Code5)
WITH SCHEMABINDING
Run Code Online (Sandbox Code Playgroud)
其中实体字段Classificator1ID..Classificator5ID已解析为分类器值Code1..Code5
并且此视图上有很多索引:
CREATE UNIQUE CLUSTERED INDEX [IXUC_EntityView$ID] ON EntityView
([ID]);
CREATE UNIQUE NONCLUSTERED INDEX [IXU_EntityView$ID$include$ALL] ON EntityView
([ID]) INCLUDE (Code1, Code2, Code3, Code4, Code5);
CREATE UNIQUE NONCLUSTERED INDEX [IXU_EntityView$ALL] ON EntityView
([ID],Code1, Code2, Code3, Code4, Code5);
CREATE UNIQUE NONCLUSTERED INDEX [IXU_EntityView$ID$Code1] ON EntityView
([ID],Code1);
CREATE UNIQUE NONCLUSTERED INDEX [IXU_EntityView$ID$include$Code1] ON EntityView
([ID])INCLUDE (Code1);
CREATE NONCLUSTERED INDEX [IX_EntityView$Code1] ON EntityView
(Code1);
CREATE NONCLUSTERED INDEX [IX_EntityView$Code1$include$ID] ON EntityView
(Code1) INCLUDE (ID);
Run Code Online (Sandbox Code Playgroud)
但QO从不使用它们!试试这个:
SELECT * FROM EntityView;
SELECT ID, Code1 FROM EntityView;
SELECT ID, Code1, Code2, Code3, Code4, Code5 FROM EntityView;
SELECT ID, Code1, Code2, Code3, Code4, Code5 FROM EntityView WHERE ID=1;
SELECT ID, Code1 FROM EntityView Where Code1 like 'NR%';
Run Code Online (Sandbox Code Playgroud)
为什么?尤其是"包含"索引有什么问题?创建索引,包含所有字段但仍未使用...
补充:这只是测试!请不要这么生气,不要逼我去分析那些指标的致瘾问题.
在我的真实项目中,我无法解释为什么QO会忽略索引视图(非常非常有用的索引视图).但有时我看到它在其他地方使用它们.我创建了这个db片段来试验索引公式,但可能我应该做更多的事情:以某种方式调整statistcs?
tl;dr 回答:如果您不指定 NOEXPAND,查询优化器不知道您正在提交一个简单的视图选择。它必须将查询的扩展(这是它看到的全部内容)与某些视图索引相匹配。当它是一个带有一堆演员表的五向连接时,可能不会打扰。
查看与查询的索引匹配是一个难题,我相信您的视图对于查询引擎来说太复杂了,无法与索引匹配。考虑一下您的查询之一:
SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';
Run Code Online (Sandbox Code Playgroud)
很明显,这可以使用视图索引,但这不是查询引擎看到的查询。如果您不指定 NOEXPAND,视图会自动展开,所以这就是查询引擎的内容:
SELECT ID, Code1 FROM (
SELECT e.ID, 'NR'+CAST(c1.CODE as nvarchar(11)) as Code1, 'NR'+CAST(c2.CODE as nvarchar(11)) as Code2, 'NR'+CAST(c3.CODE as nvarchar(11)) as Code3, 'NR'+CAST(c4.CODE as nvarchar(11)) as Code4, 'NR'+CAST(c5.CODE as nvarchar(11)) as Code5
FROM dbo.Entity e
inner join dbo.Classificator1 c1 on e.ID = c1.ID
inner join dbo.Classificator2 c2 on e.ID = c2.ID
inner join dbo.Classificator3 c3 on e.ID = c3.ID
inner join dbo.Classificator4 c4 on e.ID = c4.ID
inner join dbo.Classificator5 c5 on e.ID = c5.ID;
) AS V;
Run Code Online (Sandbox Code Playgroud)
查询引擎看到这个复杂的查询,它有描述已定义视图索引的信息(但可能不是视图定义的 SQL)。鉴于此查询和视图索引都有多个连接和强制转换,匹配是一项艰巨的工作。
请记住,您知道此查询和视图索引中的连接和匹配是相同的,但查询处理器不知道这一点。它处理这个查询就像它加入了 Classificator3 的五个副本,或者如果其中一列是 'NQ'+CAST(c2.CODE as varchar(12))。视图索引匹配器(假设它试图匹配这个复杂的查询)必须将此查询的每个细节与所涉及的表上的视图索引的细节相匹配。
查询引擎的第一目标是找出一种有效执行查询的方法。它可能不是为了花大量时间尝试将五向连接和 CAST 的每个细节与视图索引匹配而设计的。
如果我不得不猜测,我怀疑视图索引匹配器看到查询的结果列甚至不是任何基础表的列(因为 CAST)并且根本不费心去尝试任何事情。补充:我错了。我刚刚尝试了 Martin 的更新统计信息的建议,以使查询变得昂贵,并且在没有 NOEXPAND 的情况下,为其中一些查询匹配了视图索引。视图匹配器比我想象的更聪明!所以问题是如果成本非常高,视图匹配器可能会更努力地匹配复杂的查询。
使用 NOEXPAND 提示,而不是期望查询引擎能够找出此处匹配的内容。NOEXPAND 绝对是你的朋友,因为这样查询引擎就会看到
SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';
Run Code Online (Sandbox Code Playgroud)
然后对于视图索引匹配器来说很明显有一个有用的索引。
(注意:您的 SQL Fiddle 代码包含对同一个表的所有 5 个外键引用,这可能不是您想要的。)
在 2012 Developer Edition 上运行,无提示查询的成本大约是提示查询的 8 倍
虽然 8 的系数听起来可能很大,但您的示例数据非常小,并且直接从基表中选择的成本与0.0267122从0.003293视图中估计的成本相当。
保罗·怀特 (Paul White) 解释道他的回答中解释说,如果首先找到足够低的计划,甚至不会考虑自动索引视图匹配。
人为地提高所有涉及表的成本
UPDATE STATISTICS Classificator1 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000
UPDATE STATISTICS Classificator2 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000
UPDATE STATISTICS Classificator3 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000
UPDATE STATISTICS Classificator4 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000
UPDATE STATISTICS Classificator5 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000
UPDATE STATISTICS Entity WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000
Run Code Online (Sandbox Code Playgroud)
将基表计划的成本增加到 29122.6
您现在应该看到视图正在匹配(在企业版/开发版/评估版上),除非您明确提示否则。
SELECT * FROM EntityView;
SELECT * FROM EntityView OPTION (EXPAND VIEWS)
Run Code Online (Sandbox Code Playgroud)

| 归档时间: |
|
| 查看次数: |
4121 次 |
| 最近记录: |