选择索引视图的聚集索引有哪些因素?


19

简而言之
,查询优化器选择索引视图索引时会考虑哪些因素?

对我来说,索引视图似乎无视我对Optimizer如何选择索引的理解。我以前看过这个问题,但是OP不太受欢迎。 我确实在寻找路标,但是我将伪造一个伪示例,然后发布带有大量DDL,输出和示例的真实示例。

假设我使用的是Enterprise 2008+,请理解 with(noexpand)

伪示例

以这个伪示例为例:我创建一个具有22个联接,17个过滤器和一个马戏团小马的视图,该马戏小马穿过一千万个行表。这种观点很昂贵(是的,用大写字母E)可以实现。我将对SCHEMABIND进行索引并为视图建立索引。然后一个 SELECT a,b FROM AnIndexedView WHERE theClusterKeyField < 84。在Optimizer逻辑中,我无法进行底层联接。

结果:

  • 没有提示:4825读取720行,在76ms内读取47 cpu,估计的子树开销为0.30523。
  • 使用提示:17次读取,720行,4 ms内15 cpu,估计的子树成本为0.007253

那么这是怎么回事?我已经在Enterprise 2008、2008-R2和2012中进行了尝试。通过每一个度量标准,我都认为使用视图索引的效率大大提高。我没有参数嗅探问题或数据偏斜,因为这是广告问题。

一个真实(长)的例子

除非您是一个受虐狂,否则您可能不需要或不想阅读此部分。

是的
,企业

Microsoft SQL Server 2012-11.0.2100.60(X64)2012年2月10日19:39:15版权所有(c)Windows NT 6.2(Build 9200:)上的Microsoft Corporation Enterprise Edition(64位)(Hypervisor)

风景

CREATE VIEW dbo.TimelineMaterialized    WITH SCHEMABINDING
AS
SELECT  TM.TimelineID,
        TM.TimelineTypeID,
        TM.EmployeeID,
        TM.CreateUTC,
        CUL.CultureCode,
        CASE 
           WHEN TM.CustomerMessageID    > 0 THEN TM.CustomerMessageID
           WHEN TM.CustomerSessionID    > 0 THEN TM.CustomerSessionID
           WHEN TM.NewItemTagID         > 0 THEN TM.NewItemTagID
           WHEN TM.OutfitID             > 0 THEN TM.OutfitID
           WHEN TM.ProductTransactionID > 0 THEN TM.ProductTransactionID
           ELSE 0 END  As HrefId,
        CASE 
          WHEN TM.CustomerMessageID    > 0 THEN IsNull(C.Name, 'N/A')   
          WHEN TM.CustomerSessionID    > 0 THEN IsNull(C.Name, 'N/A')
          WHEN TM.NewItemTagID         > 0 THEN IsNull(NI.Title, 'N/A')
          WHEN TM.OutfitID             > 0 THEN IsNull(O.Name, 'N/A')
          WHEN TM.ProductTransactionID > 0 THEN IsNull(PT_PL.NameLocalized, 'N/A')
                 END as HrefText

FROM       dbo.Timeline TM
INNER JOIN dbo.CustomerSession    CS    ON TM.CustomerSessionID    = CS.CustomerSessionID
INNER JOIN dbo.CustomerMessage    CM    ON TM.CustomerMessageID    = CM.CustomerMessageID
INNER JOIN dbo.Outfit             O     ON PO.OutfitID             = O.OutfitID
INNER JOIN dbo.ProductTransaction PT    ON TM.ProductTransactionID = PT.ProductTransactionID
INNER JOIN dbo.Product            PT_P  ON PT.ProductID            = PT_P.ProductID
INNER JOIN dbo.ProductLang        PT_PL ON PT_P.ProductID          = PT_PL.ProductID
INNER JOIN dbo.Culture            CUL   ON PT_PL.CultureID         = CUL.CultureID
INNER JOIN dbo.NewsItemTag        NIT   ON TM.NewsItemTagID        = NIT.NewsItemTagID
INNER JOIN dbo.NewsItem           NI    ON NIT.NewsItemID          = NI.NewsItemID
INNER JOIN dbo.Customer           C     ON  C.CustomerID = CASE 
                                             WHEN TM.TimelineTypeID = 1 THEN CM.CustomerID 
                                             WHEN TM.TimelineTypeID = 5 THEN CS.CustomerID
                                             ELSE 0 END

WHERE        CUL.IsActive = 1

聚集索引

CREATE UNIQUE CLUSTERED INDEX PK_TimelineMaterialized  ON 
                   TimelineMaterialized (EmployeeID, CreateUTC, CultureCode, TimelineID)

测试SQL

-- NO HINT - - -  - - -  - - -  - - -  - - - 
SELECT  *                 --yes yes, star is bad ...just a test example
FROM    TimelineMaterialized TM 
WHERE 
            TM.EmployeeID   = 2
        AND TM.CultureCode  = 'en-US'
        AND TM.CreateUTC    > '9/10/2012'
        AND TM.CreateUTC    < '9/11/2012'

-- WITH HINT - - -  - - -  - - -  - - -  - - - 
SELECT  *               
FROM    TimelineMaterialized TM with(noexpand)
WHERE 
            TM.EmployeeID   = 2
        AND TM.CultureCode  = 'en-US'
        AND TM.CreateUTC    > '9/10/2012'
        AND TM.CreateUTC    < '9/11/2012'

结果= 11行输出

11行输出-两个查询相同

Profiler输出
前4行没有提示。底部的4行使用提示。

探查器

执行计划
GitHub Gist的两个SQLPlan格式的执行计划

没有提示执行计划-为什么不使用我给您的SQL先生的聚簇索引?它聚集在3个过滤器字段上。试试吧,您可能会喜欢。
没有提示-庞大的执行计划

使用提示时的简单计划。

使用提示-简单执行计划


Answers:


26

匹配索引视图是一项相对昂贵的操作*,因此优化器会首先尝试其他快速便捷的转换。如果这些碰巧产生了便宜的计划(在您的情况下为0.05个单位),优化将尽早结束。可以肯定的是,持续优化将比其节省的时间更多。请记住,优化器的主要目标是迅速制定“足够好的”计划。

在视图上使用聚簇索引本身并不昂贵,但是将逻辑查询树与潜在索引视图匹配的过程可能会很昂贵。正如我在对另一个问题的评论中提到的那样,查询中的视图引用在优化之前已展开,因此优化器不知道您首先针对视图编写了查询-它仅看到展开的树(就像该视图已插入)。

“良好的计划”意味着优化程序找到了一个不错的计划,并在探索阶段的早期就停止了。“超时”表示在当前阶段开始时,它超出了自己设置为“预算”的优化步骤的数量。

预算是根据上一阶段中最佳计划的成本确定的。使用这样的低成本查询(0.05),预算移动的数量将非常小,并且由于样本查询中涉及的连接数量而被常规转换很快耗尽(例如,有很多方法可以重新排列内部连接) 。

如果您有兴趣了解为什么索引视图匹配昂贵,并因此留待优化的后期阶段和/或仅考虑进行更昂贵的查询,请参阅此处(pdf)和此处(citeseer )的两篇Microsoft研究论文。)。

另一个相关因素是,索引视图匹配在优化阶段0(事务处理)中不可用。

进一步阅读:

索引视图和统计

*并且仅在企业版(或等效版本)中可用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.