简体   繁体   English

为什么Query Optimizer完全忽略索引视图索引?

[英]Why Query Optimizer totally ignores indexed view indexes?

SQL Fiddle: http://sqlfiddle.com/#!6/d4496/1 (data is pre-generated for your experiments) SQL小提琴: http ://sqlfiddle.com/#!6/d4496/1(为您的实验预先生成数据)

There is obvious table: 有明显的表:

CREATE TABLE Entity 
(
  ID int,
  Classificator1ID int,
  Classificator2ID int,
  Classificator3ID int,
  Classificator4ID int,
  Classificator5ID int
);

and the view : 和观点:

CREATE VIEW dbo.EntityView (ID, Code1, Code2, Code3, Code4, Code5) 
WITH SCHEMABINDING

where entities fields Classificator1ID..Classificator5ID resolved to classificators values Code1..Code5 其中实体字段Classificator1ID..Classificator5ID解析为分类符值Code1..Code5

and there are a lot of indexes on this view: 并且此视图上有很多索引:

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

But QO never use them! 但QO从不使用它们! Try this: 试试这个:

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%';

Why? 为什么? And especially What is wrong with "include" indexes? 尤其是“包含”索引有什么问题? index created , has all fields and still unused... 创建索引,包含所有字段但仍未使用...

ADDED: THIS IS JUST TEST! 补充:这只是测试! Please do not be so angry and do not push me to analyze those indexes maitinence problems. 请不要这么生气,不要逼我去分析那些指标的致瘾问题。

In my real project I can't explain why QO ignores indexed views (very-very usefull indexed views). 在我的真实项目中,我无法解释为什么QO会忽略索引视图(非常非常有用的索引视图)。 But sometimes I see it utilize them in other places. 但有时我看到它在其他地方使用它们。 I have created this db snippet to experiment with index formulas but may be I should do something more: tune statistcs somehow ? 我创建了这个db片段来试验索引公式,但可能我应该做更多的事情:以某种方式调整statistcs?

Running on 2012 Developer Edition the unhinted query is costed at approx 8 times more than the hinted query 在2012 Developer Edition上运行时,未提示的查询的成本约为提示查询的8倍

在此输入图像描述

Whilst a factor of 8 might sound a lot your example data is pretty small and the cost for selecting directly from the base tables is 0.0267122 vs 0.003293 for the estimated cost from the view. 虽然8倍听起来你的很多示例数据是非常小,直接从基表中选择的成本是0.0267122 VS 0.003293从视图中的预计成本。

Paul White explains in his answer here that automatic indexed view matching won't even be considered if a low enough plan is found first. Paul White在他的回答中解释说,如果首先找到足够低的计划,则甚至不会考虑自动索引视图匹配。

Artificially bumping up the costs for all the tables involved 人为地提高所有相关表的成本

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 

Increases the cost of the base table plan to 29122.6 将基表计划的成本增加到29122.6

You should now see the view being matched (on Enterprise/Developer/Evaluation editions) unless you explicitly hint otherwise. 您现在应该看到视图匹配(在Enterprise / Developer / Evaluation版本上),除非您明确暗示其他情况。

SELECT * FROM EntityView;

SELECT * FROM EntityView OPTION (EXPAND VIEWS) 

在此输入图像描述

tl;dr answer: If you don't specify NOEXPAND, the query optimizer has no idea you are submitting a simple select from a view. tl;博士回答:如果你没有指定NOEXPAND,查询优化器不知道你是从视图中提交一个简单的选择。 It would have to match the expansion of your query (which is all it sees) with some view index. 它必须与您的查询(它看到的全部)的扩展匹配一些视图索引。 Probably won't bother when it's a five-way join with a bunch of casts. 当它与一堆演员阵容进行五方联接时,可能不会打扰。

View index matching to a query is a hard problem, and I believe your view is too complicated for the query engine to match to an index. 查看与查询匹配的索引是一个难题,我相信您的视图太复杂,查询引擎无法匹配索引。 Consider this one of your queries: 考虑一下这个问题:

SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';

It's obvious to you that this can use a view index, but this is not the query the query engine sees. 很明显,这可以使用视图索引,但这不是查询引擎看到的查询。 Views are automatically expanded if you don't specify NOEXPAND, so this is what goes to the query engine: 如果您未指定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;

The query engine sees this complicated query, and it has information (but probably not SQL of view definitions) that describe view indexes that have been defined. 查询引擎看到这个复杂的查询,它具有描述已定义的视图索引的信息(但可能不是视图定义的SQL)。 Given that this query and the view indexes both have multiple joins and casts, matching is a hard job. 鉴于此查询和视图索引都具有多个连接和强制转换,匹配是一项艰巨的任务。

Keep in mind that you know the joins and matches are identical in this query and the view indexes, but the query processor doesn't know that. 请记住,您知道此查询和视图索引中的连接和匹配是相同的,但查询处理器不知道这一点。 It treats this query just the same as if it joined five copies of Classificator3, or if one of the columns was 'NQ'+CAST(c2.CODE as varchar(12)). 它对此查询的处理方式与加入Classificator3的五个副本相同,或者其中一个列是'NQ'+ CAST(c2.CODE as varchar(12))。 The view index matcher (assuming it made any attempt to match this complicated a query) would have to match every detail of this query to the details of view indexes on the tables involved. 视图索引匹配器(假设它尝试匹配此复杂的查询)必须将此查询的每个细节与所涉及的表上的视图索引的详细信息相匹配。

The query engine has as its #1 goal to figure out a way to execute the query efficiently. 查询引擎的第一目标是找出一种有效执行查询的方法。 It's probably not designed to spend a lot of time trying to match every detail of a five-way join and CASTs to a view index. 它可能不会花费大量时间来尝试将五向连接和CAST的每个细节与视图索引相匹配。

If I had to guess, I suspect the view index matcher sees that the result columns of the query are not even columns of any underlying table (because of the CAST) and simply doesn't bother trying anything. 如果我不得不猜测,我怀疑视图索引匹配器看到查询的结果列不是任何基础表的列(因为CAST),并且根本不打算尝试任何东西。 Added : I'm wrong. 补充我错了。 I just tried Martin's suggestion of updating statistics to make the query expensive, and a view index was matched for some of these queries without NOEXPAND. 我刚刚尝试了Martin关于更新统计信息以使查询变得昂贵的建议,并且在没有NOEXPAND的情况下,其中一些查询匹配了视图索引。 The view matcher is cleverer than I thought! 视图匹配器比我想象的更聪明! So the issue is that the view matcher probably tries harder to match a complicated query if its cost is very high. 所以问题是视图匹配器可能更难以匹配复杂的查询,如果它的成本非常高。

Use the NOEXPAND hint instead of expecting the query engine to be able to figure out what matches here. 使用NOEXPAND提示而不是期望查询引擎能够找出匹配的内容。 NOEXPAND is absolutely your friend, because then the query engine gets to see NOEXPAND绝对是你的朋友,因为那时查询引擎可以看到

SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';

and it's then immediately obvious to the view index matcher that there is a useful index. 然后,对于视图索引匹配器来说,显然有一个有用的索引。

(Note: Your SQL Fiddle code has all 5 foreign key references to the same table, which is probably not what you want.) (注意:您的SQL小提琴代码具有对同一个表的所有5个外键引用,这可能不是您想要的。)

Use the WITH (NOExpand) hint if you are on SQL Server Enterprise 如果您使用的是SQL Server Enterprise,请使用WITH(NOExpand)提示

Your query would be SELECT * FROM EntityView with (noexpand) 您的查询将是SELECT * FROM EntityView with (noexpand)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 优化程序将忽略唯一筛选索引和索引视图 - Unique filtered index and indexed view are ignored by optimizer 索引视图与表上的索引 - Indexed View vs Indexes on Table SQL查询性能更好,使用带索引的实际非规范化表而不是索引视图? - Better for SQL Query performance to use an actual denormalized table with indexes rather than an indexed view? 使用视图索引的Azure数据库查询优化器 - Azure Database Query Optimizer using View Indices 为什么索引视图会实现? - Why does indexed view materialize? SQL Server查询优化器如何从特定表的可用索引中选择非聚集索引? - How does the SQL Server query optimizer choose non clustered indexes from available indexes for particular table? 这些是按小时/天/月分组的排行榜索引视图的正确索引吗? - Are these the correct Indexes for an Indexed View for Leaderboards Grouped By Hour/Day/Month? 针对非索引视图优化选择查询 - Optimize select query for non-indexed view 带有datepart的索引视图,对datepart的查询未使用索引 - Indexed view with datepart, query on datepart is not using the index 为什么查询优化器选择完全不同的查询计划? - Why query optimizer selects completely different query plans?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM