AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 26979
Accepted
EBarr
EBarr
Asked: 2012-10-16 09:47:57 +0800 CST2012-10-16 09:47:57 +0800 CST 2012-10-16 09:47:57 +0800 CST

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

  • 772

简而言之
,查询优化器选择索引视图的索引有哪些因素?

对我来说,索引视图似乎违背了我对优化器如何选择索引的理解。我以前见过这个问题,但是 OP 并没有受到太大的欢迎。 我真的在寻找路标,但我会编造一个伪示例,然后发布带有大量 DDL、输出、示例的真实示例。

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

伪示例

以这个伪示例为例:我创建了一个包含 22 个连接、17 个过滤器和一个跨越 1000 万行表的马戏团小马的视图。这种观点实现起来很昂贵(是的,大写的 E)。我将对视图进行 SCHEMABIND 和索引。然后一个 SELECT a,b FROM AnIndexedView WHERE theClusterKeyField < 84. 在我无法理解的优化器逻辑中,执行了底层连接。

结果:

  • 无提示:720 行 4825 次读取,47 cpu 超过 76 毫秒,估计子树成本为 0.30523。
  • 提示:17 次读取,720 行,15 个 CPU 超过 4 毫秒,估计子树成本为 0.007253

那么这里发生了什么?我已经在Enterprise 2008、2008-R2 和 2012 中尝试过。根据我能想到的每一个指标,使用视图索引的效率要高得多。我没有参数嗅探问题或倾斜数据,因为这是临时性的。

一个真实(长)的例子

除非你是一个触摸受虐狂,否则你可能不需要或不想阅读这部分。


是的,企业版。

Microsoft SQL Server 2012 - 11.0.2100.60 (X64) Feb 10 2012 19:39:15 版权所有 (c) Microsoft Corporation Enterprise Edition (64-bit) o​​n Windows NT 6.2 (Build 9200:) (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 行正在使用提示。

探查器

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

No Hint 执行计划——为什么不使用 SQL 先生给你的聚集索引呢?它聚集在 3 个过滤器字段上。试试看,你可能会喜欢。
没有提示 - 巨大的执行计划

使用提示时的简单计划。

使用提示 - 简单的执行计划

sql-server index-tuning
  • 1 1 个回答
  • 2576 Views

1 个回答

  • Voted
  1. Best Answer
    Paul White
    2012-10-17T07:30:47+08:002012-10-17T07:30:47+08:00

    匹配索引视图是一项相对昂贵的操作*,因此优化器首先尝试其他快速简单的转换。如果这些碰巧产生了一个便宜的计划(在你的情况下是 0.05 个单位),那么优化就会提前结束。赌注是,持续优化会消耗更多的时间而不是节省的时间。请记住,优化器的主要目标是快速制定“足够好”的计划。

    在视图上使用聚集索引本身并不昂贵,但是将逻辑查询树与潜在的索引视图匹配的过程可以。正如我在另一个问题的评论中提到的,查询中的视图引用在优化之前被扩展,所以优化器不知道你首先针对视图编写了查询——它只看到扩展的树(好像该视图已内联)。

    “足够好的计划”意味着优化器找到了一个不错的计划并在探索阶段早期停止。“超时”意味着它超过了它在当前阶段开始时将自己设置为“预算”的优化步骤数。

    预算是根据在前一阶段找到的最佳计划的成本设置的。对于这样一个低成本查询(0.05),预算移动的数量将非常少,并且考虑到示例查询中涉及的连接数量(例如,有很多方法可以重新排列内部连接),定期转换会很快耗尽.

    如果您有兴趣了解更多关于为什么索引视图匹配很昂贵,因此留给后期优化阶段和/或只考虑用于更昂贵的查询,这里有两篇关于该主题的 Microsoft 研究论文( pdf) 和这里(citeseer )。

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

    进一步阅读:

    索引视图和统计信息

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

    • 26

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve