本文出处:http://www.cnblogs.com/wy123/p/6694933.html

第一次通过索引视图优化SQL语句,以及遇到的一些问题,记录一下。

语句分析

最近开发递交过来一个查询统计的SQL,说是性能有问题,原本执行需要4-5秒钟,这个业务本身对性能要求又比较critical,期望是在1s之内
在用尽各种办法之后(执行计划,统计信息,索引,改写SQL,临时表拆分),依然没有实质性的改观,
在观察SQL本身的特点之后,
有以下几个特点
  1,查询语句整体为多表join,但是每个表自身的数据并不是非常大,百万级
  2,查询结果在主表上一个较大的时间范围的数据进行Count的聚合操作
  3,几张表之间除了连接条件,主要是进行了一些比较复杂的逻辑运算(下面截图可以看到,没多少IO,CPU时间却很高)
    不过表的连接方式都是inner join,主要性能点就在于表关联之间的Hash join之间的逻辑运算,参考下图(是执行计划的一部分)

  通过统计信息发现,该SQL语句的物理IO并不高,说明索引没有什么问题,通过索引改善IO可能改善空间很有限
  时间主要花费在SQL语句的编译和的Hash join 运算
  尝试改写借助SQL之后(纯改写SQL和借助临时表拆分语句),发现依然很难绕过Hash join,主要是表之间的逻辑运算最为耗时
  最后想到可以先将运算好的的数据物理存储起来,然后改写查询的SQL语句完成等价的查询,
  避免每次查询都做复杂的逻辑运算,应该可以有比较大的改善,于是就想到了索引视图

  

创建索引视图改写SQL

  在提取出来原始的查询SQL,创建索引视图,并在索引视图上创建unique cluster index和合理的nocluster index
  通过索引视图改写原始的查询统计SQL语句,
  改写后的SQL语句是一个索引视图替代原始的4张表,与另外一个物理表join,发现效率上没有任何改善,
  观察改写后的SQL语句的执行计划,发现跟原始SQL一样,并没有走索引视图上的索引,或者说是用到索引视图,一时间觉得好心塞,实在没招了
  执行计划依旧是长长的一大段,然后依旧是好几个Hash Join.参考下图,执行计划跟本文第一个截图一模一样

  按道理,索引视图固化结果集,并且根据情况做了过滤,结果集是原始查询的一部分而已,
  用同样的查询条件从索引视图做查询统计,走索引视图代价肯定要比原始SQL低,通过强制不展开with(noexpand)提示,证实了这个推断
  如下是强制不展开索引视图的统计信息,可以看到完全达到了预期的1S之内

  

  当然索引视图也不是没有代价,在一定程度上牺牲了数据写入的效率和冗余存储,来换取查询的效率
  之前简单介绍过索引视图的一些特点 http://www.cnblogs.com/wy123/p/6041122.html

索引视图被展开(expand)的原因分析

  最关键的问题在于,没有强制不展开索引视图(with(noexpand)提示)的情况下,为什么没有走索引视图呢?

  这个问题确实郁闷了一阵子,整个半天都在想这个问题,因为索引视图本身用的就少,出现此问题更是一头雾水,不过Google一下,还有一大把类似的问题
  如下是在google的时候查到的,原文是英文,大概意思如下,非直译。

  参考链接:http://dba.stackexchange.com/questions/26979/what-factors-go-into-an-indexed-views-clustered-index-being-selected/27039#27039

索引视图的匹配(查询用索引视图替代而不走原始的基础表)是一个相当昂贵的操作,因此优化器试图通过其他方式快速转换(生成执行计划)
如果优化器产生了一个相对优化的执行计划,就可以尽早结束(不必继续生成其他执行计划)
问题就在于:继续生成其他执行计划的代价要大于已生成的执行计划的代价
听起来有点别扭,
之前举过这么一个例子,比如说是花3秒钟找到一个相对优化的执行计划,这个执行计划完成SQL的执行需要2秒钟
与花10秒钟的时候找到一个最优化的执行计划,尽管这个执行计划完成SQL的执行可能只需要0.5秒钟,虽然后者的执行计划更优,但整体代价更大
优化器的主要目标是尽快找到一个足够好的执行计划(而非总是生成最好的执行计划)

使用索引视图本身并不是一个昂贵的操作,
但是与潜在索引视图中匹配逻辑查询树确实一个代价较大的行为,在查询涉及的视图在优化器优化之前已经被展开
因此优化器并不知道你的查询是否未被了索引视图,他看到的只是展开的查询树
这个通俗地讲就是:
让sqlserver知道,一个查询,可以用索引视图中的结果等价替代视图逻辑中原始的基表,是一个代价较大的过程
因为SQL Server根据原始的基础表,生成一种执行计划之后,就不去判断是否可以用索引视图做等价替代。

  当然白皮书里有更详细的介绍,里面索引视图相关的一些逻辑实现和分析http://www.cs.cmu.edu/~natassa/courses/15-823/current/papers/vldb00.pdf

最后多逼逼一句:
  上面的白皮书实在看不懂,只是Google出来说详细信息请看这个参考资料,
  这里只是从现象去推断优化器在面对索引视图的一些特性,了解到内在机制的一些特点,可能潜在的问题,以及对应的解决办法
  这里又提开源软件了,别说不开源了,即便是开源了,除了钱的因素,在技术上,有几个人可以动一下这些大型软件的核心代码?
  我并不是在黑开源软件啊,只是听有人说,开源好啊,有源码怎么怎么样,觉得够装13的,
  国内除了bat等少数几家公司做过修改源码,做过开源数据库的定制,试问还有多少家可以修改数据库源码然后上生产使用

  最近在学MySQL,继续SQL Server下去恐怕踏马要失业了,开源,对大多数公司来说,钱才是一个大头因素吧,尼玛跑题了。

  

SQL Server 优化---为什么索引视图(物化视图)需要with(noexpand)强制查询提示的更多相关文章

  1. Sql Server优化之索引提示----我们为什么需要查询提示,Sql Server默认情况下优化策略选择的不足

    环境: Sql Server2012 SP3企业版,Windows Server2008 标准版 问题由来: 最近在做DB优化的时候,发现一个存储过程有非常严重的性能问题, 由于整个SP整体逻辑是一个 ...

  2. SQL Server 调优系列玩转篇一(如何利用查询提示(Hint)引导语句运行)

    前言 前面几篇我们分析了关于SQL Server关于性能调优的一系列内容,我把它分为两个模块. 第一个模块注重基础内容的掌握,共分7篇文章完成,内容涵盖一系列基础运算算法,详细分析了如何查看执行计划. ...

  3. SQL Server 2000 ——系统表和系统视图

    一.系统表 数据字典的详细信息请查SQL SERVER BOL,这里仅列出一部分. 1.1.sysservers 1.查看所有本地服务器及链接服务器 select * from master..sys ...

  4. SQL Server基础之索引

     索引用于快速找出在某个列中有某一特定值的行,不使用索引,数据库必须从第一条记录开始读完整个表,直到找出相关的行.表越大,查询数据所花费的时间越多,如果表中查询的列有一个索引,数据库能快速到达一个位置 ...

  5. 转载: SQL Server中的索引

    http://www.blogjava.net/wangdetian168/archive/2011/03/07/347192.html 1 SQL Server中的索引 索引是与表或视图关联的磁盘上 ...

  6. [SQL Server优化]善用系统监视器,确定系统瓶颈

    原文:[SQL Server优化]善用系统监视器,确定系统瓶颈 来自: http://hi.baidu.com/solorez/blog/item/f82038fa0e71b78d9e51468c.h ...

  7. 深入SQL Server优化【推荐】

    深入sql server优化,MSSQL优化,T-SQL优化,查询优化 十步优化SQL Server 中的数据访问故事开篇:你和你的团队经过不懈努力,终于使网站成功上线,刚开始时,注册用户较少,网站性 ...

  8. SQL Server优化的方法

    SQL Server优化的方法<一>   查询速度慢的原因很多,常见如下几种:   1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)   2.I/O吞吐量小,形成了 ...

  9. Sql Server优化之路

    本文只限coder级别层次上对Sql Server的优化处理简结,为防止专业DB人士有恶心.反胃等现象,请提前关闭此页面. 首先得有一个测试库,使用数据生成计划生成测试数据库(参考:http://de ...

随机推荐

  1. JVM调优常用参数

    JVM常用参数配置 -Xmx2048m 最大堆大小 -Xms1024m 初始堆大小 -Xmn1024m 年轻代大小 -XX:SurvivorRatio=8 Eden区与Survivor区的大小比值,设 ...

  2. python程序化交易神器——tushare

    一直想试着将自己的交易思路程序化,可惜困难重重 ,连第一步获取数据都要花很多精力,直到最近发现了Tushare,不仅使用非常便利,功能也无比强大,股票.期货.基金.财经新闻,甚至电影票房等都可以非常便 ...

  3. linux中 shell编程 判断服务是否运行

    判断nginx是否运行中: if ps -ef|grep "nginx"|egrep -v grep >/dev/null then echo ok! else echo n ...

  4. mapreduce深入剖析5大视频

    参考代码 TVPlayCount.java package com.dajiangtai.hadoop.tvplay; import java.io.IOException; import org.a ...

  5. WebView长按保存图片;WebView不跳转到系统的浏览器;WebView加载显示进度条;WebView返回事件处理;

    直接看代码即可,代码里面注释写的很清楚,这个类拉下来就能用: 写法和命名比较粗暴,但也简单易懂: public class MainActivity extends AppCompatActivity ...

  6. centos7 安装、使用git

    1. 查看系统是否已经安装git git --version 2. 安装git yum install -y git 3. 查看是否安装成功 git --version 4. 卸载 yum remov ...

  7. 网易云音乐mp3外链、真实地址下载方法

    一个网易音乐外链地址长期有效,很简单的方法: 第一步打开网易云音乐,随便找到一首歌,播放,复制网址的ID, 例如:杨钰莹的心雨,网址是: http://music.163.com/#/song?id= ...

  8. 【接口测试】【SOAP】简单的接口测试学习

    ==================================================================================================== ...

  9. [C#]通过反射访问类私有成员

    参考链接: https://www.cnblogs.com/adodo1/p/4328198.html 代码如下: using System; using System.Reflection; usi ...

  10. Mybatis十( mybatis其他使用)

    1.批量执行 public void addUser(User user); <insert id="addUser" parameterType="model.U ...