我们知道sql在底层的执行给我们上层人员开了一个窗口,那就是执行计划,有了执行计划之后,我们就清楚了那些烂sql是怎么执行的,这样

就可以方便的找到sql的缺陷和优化点。

一:执行计划生成过程

  说到执行计划,首先要知道的是执行计划大概生成的过程,这样就可以做到就心中有数了,下面我画下简图:

1. 分析过程

  这三个比较容易理解,首先我们要保证sql的语法不能错误,select和join的表是必须存在的,以及你是有执行这个sql的权限,对不对。。。

这样我们就走完了执行计划生命周期的第一个流程。

2. 编译过程

保证了上面sql这三点的话,引擎就必须硬着头皮看你这么一大坨烂sql,该删的删,该改的改,该转换的转换,比如说你的“子查询”会转化为

“表连接”等等。。。其实也挺难为引擎的,举个例子吧。

<1>子查询生成的sql:

<2>join生成的sql:

从上面的两个结果中,你可以看到,大家都是玩join的,如果你仔细看的话,会发现一个是“哈希匹配”,一个是“嵌套循环”,为什么不一样,这

当然是引擎根据很多情况综合评选出来的,比如说:磁盘IO,逻辑读,资源占用,硬件环境等等。。。这也是所谓的“计划选优”操作。

3.执行过程

  既然执行计划都选出来了,理所当然就要执行了,执行完后会把sql和执行计划放入缓存,这样下次有同样的sql过来的时候就可以直接从

Cache中提取了,不需要再次生成计划了,你也看到,生成执行计划还是比较消耗CPU时间的。

二:看看sql和执行的计划的缓存

  刚才也说了,sql和plan都已经放入缓存了,那我的好奇心比较强,我就想看看sql和plan到底在哪,并且长的是个什么丑样子,刚好

sqlserver还是比较能够满足我们G点的。

1. 为了方便查看缓存,我需要先将所有的缓存清空,比如下面的语句。

DBCC freeproccache
SELECT c.* FROM dbo.Category AS c
JOIN dbo.Product AS p
ON c.CategoryId=p.CategoryId
WHERE c.CategoryId=23794

2. 通过sys.dm_exec_cached_plans拿到sql和plan的指针(plan_handle),如下图

SELECT * FROM sys.dm_exec_cached_plans

从图中你看到了两个adhoc(即时查询),分别是我在第一步执行的join查询和我在第二步执行的这个select。

3. 现在我们已经拿到了2个adhoc的plan_handle,然后通过dm_exec_sql_text查看他们的sql分别是怎样?

4. 看完text缓存,接下来我们继续看看sql的plan缓存在哪?可以通过dm_exec_query_plan来查看。

上面的query_plan字段就是所谓的执行计划,以xml的形式保存在字段中。。。所以说解析这个xml还是很费时间的。。。

 <?xml version="1.0"?>
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.1" Build="10.0.1600.22">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementText="SELECT c.* FROM dbo.Category AS c
JOIN dbo.Product AS p
ON c.CategoryId=p.CategoryId
WHERE c.CategoryId=23794" StatementId="1" StatementCompId="1" StatementType="SELECT" StatementSubTreeCost="1.33278" StatementEstRows="1.03803" StatementOptmLevel="FULL" QueryHash="0xB10B821B9B5E6396" QueryPlanHash="0x8C7B3B1660E28D16">
<StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false" />
<QueryPlan CachedPlanSize="16" CompileTime="2" CompileCPU="2" CompileMemory="168">
<MissingIndexes>
<MissingIndexGroup Impact="99.4633">
<MissingIndex Database="[MYPETSHOP]" Schema="[dbo]" Table="[Product]">
<ColumnGroup Usage="EQUALITY">
<Column Name="[CategoryId]" ColumnId="2" />
</ColumnGroup>
</MissingIndex>
</MissingIndexGroup>
<MissingIndexGroup Impact="99.4636">
<MissingIndex Database="[MYPETSHOP]" Schema="[dbo]" Table="[Product]">
<ColumnGroup Usage="EQUALITY">
<Column Name="[CategoryId]" ColumnId="2" />
</ColumnGroup>
</MissingIndex>
</MissingIndexGroup>
</MissingIndexes>
<RelOp NodeId="0" PhysicalOp="Nested Loops" LogicalOp="Inner Join" EstimateRows="1.03803" EstimateIO="0" EstimateCPU="4.33898e-006" AvgRowSize="97" EstimatedTotalSubtreeCost="1.33278" Parallel="0" EstimateRebinds="0" EstimateRewinds="0">
<OutputList>
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="CategoryId" />
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="Name" />
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="Image" />
</OutputList>
<NestedLoops Optimized="0">
<RelOp NodeId="1" PhysicalOp="Clustered Index Seek" LogicalOp="Clustered Index Seek" EstimateRows="1" EstimateIO="0.003125" EstimateCPU="0.0001581" AvgRowSize="97" EstimatedTotalSubtreeCost="0.0032831" TableCardinality="1.00001e+006" Parallel="0" EstimateRebinds="0" EstimateRewinds="0">
<OutputList>
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="CategoryId" />
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="Name" />
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="Image" />
</OutputList>
<IndexScan Ordered="1" ScanDirection="FORWARD" ForcedIndex="0" ForceSeek="0" NoExpandHint="0">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="CategoryId" />
</DefinedValue>
<DefinedValue>
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="Name" />
</DefinedValue>
<DefinedValue>
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="Image" />
</DefinedValue>
</DefinedValues>
<Object Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Index="[PK_Category]" Alias="[c]" IndexKind="Clustered" />
<SeekPredicates>
<SeekPredicateNew>
<SeekKeys>
<Prefix ScanType="EQ">
<RangeColumns>
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Category]" Alias="[c]" Column="CategoryId" />
</RangeColumns>
<RangeExpressions>
<ScalarOperator ScalarString="(23794)">
<Const ConstValue="(23794)" />
</ScalarOperator>
</RangeExpressions>
</Prefix>
</SeekKeys>
</SeekPredicateNew>
</SeekPredicates>
</IndexScan>
</RelOp>
<RelOp NodeId="2" PhysicalOp="Clustered Index Scan" LogicalOp="Clustered Index Scan" EstimateRows="1.03803" EstimateIO="1.18831" EstimateCPU="0.0983419" AvgRowSize="11" EstimatedTotalSubtreeCost="1.28665" TableCardinality="89259" Parallel="0" EstimateRebinds="0" EstimateRewinds="0">
<OutputList />
<IndexScan Ordered="0" ForcedIndex="0" NoExpandHint="0">
<DefinedValues />
<Object Database="[MYPETSHOP]" Schema="[dbo]" Table="[Product]" Index="[PK_Product]" Alias="[p]" IndexKind="Clustered" />
<Predicate>
<ScalarOperator ScalarString="[MYPETSHOP].[dbo].[Product].[CategoryId] as [p].[CategoryId]=(23794)">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[MYPETSHOP]" Schema="[dbo]" Table="[Product]" Alias="[p]" Column="CategoryId" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Const ConstValue="(23794)" />
</ScalarOperator>
</Compare>
</ScalarOperator>
</Predicate>
</IndexScan>
</RelOp>
</NestedLoops>
</RelOp>
</QueryPlan>
</StmtSimple>
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>

  好了,到现在你应该认识到重新生成执行计划是不容易的。。。下一篇我们讨论讨论重用,重编译,重新生成等相关情况。

Sql Server之旅——第十一站 简单说说sqlserver的执行计划的更多相关文章

  1. Sql Server之旅——第五站 确实不得不说的DBCC命令

    原文:Sql Server之旅--第五站 确实不得不说的DBCC命令 今天研发中心办年会,晚上就是各自部门聚餐了,我个人喜欢喝干红,在干红中你可以体味到那种酸甜苦辣...人生何尝不是这样呢???正好 ...

  2. (转)Sql Server之旅——第八站 复合索引和include索引到底有多大区别?

    索引和锁,这两个主题对我们开发工程师来说,非常的重要...只有理解了这两个主题,我们才能写出高质量的sql语句,在之前的博客中,我所说的 索引都是单列索引...当然数据库不可能只认单列索引,还有我这篇 ...

  3. Sql Server之旅——第四站 你必须知道的非聚集索引扫描

    非聚集索引,这个是大家都非常熟悉的一个东西,有时候我们由于业务原因,sql写的非常复杂,需要join很多张表,然后就泪流满面了...这时候就 有DBA或者资深的开发给你看这个猥琐的sql,通过执行计划 ...

  4. Sql Server之旅——第七站 为什么都说状态少的字段不能建索引

    我们在学sqlserver的时候,大多教科书和前辈们都说状态少的字段不要建索引,由此带来的开销还不如不建索引,但是这句话有多少人真的知道, 或者说有多少人真的对此有比较深刻的理解,而不是听别人道听途说 ...

  5. Sql Server之旅——第六站 使用winHex利器加深理解数据页

    这篇我来介绍一个winhex利器,这个工具网上有介绍,用途大着呢,可以用来玩数据修复,恢复删除文件等等....它能够将一个file解析成 hex形式,这样你就可以对hex进行修改,然后你就可以看到修复 ...

  6. Sql Server之旅——第十三站 对锁的初步认识

    终于这个系列快结束了,马上又要过年了,没什么心情写博客...作为一个开发人员,锁机制也是我们程序员必须掌握的东西,很久之前 在学习锁的时候,都是教科书上怎么说,然后我怎么背,缺少一个工具让我们眼见为实 ...

  7. Sql Server之旅——第十站 看看DML操作对索引的影响

    我们都知道建索引是需要谨慎的,当只有利大于弊的时候才适合建,我们也知道建索引是需要维护成本的,这个维护也就在于DML操作了, 下面我们具体看看到底DML对索引都有哪些内幕.... 一:delete操作 ...

  8. Sql Server之旅——第八站 复合索引和include索引到底有多大区别?

    周末终于搬进出租房了,装了宽带....才发现没网的日子...那是一个怎样的与世隔绝呀...再也受不了那样的日子了....好了,既然网 安上去了,还得继续我的这个系列. 索引和锁,这两个主题对我们开发工 ...

  9. Sql Server之旅——第三站 解惑那些背了多年聚集索引的人

    说到聚集索引,我想每个码农都明白,但是也有很多像我这样的猥程序员,只能用死记硬背来解决这个问题,什么表中只能建一个聚集索引, 然后又扯到了目录查找来帮助读者记忆....问题就在这里,我们不是学文科,, ...

随机推荐

  1. 浅谈 C++ 中的 new/delete 和 new[]/delete[]

    在 C++ 中,你也许经常使用 new 和 delete 来动态申请和释放内存,但你可曾想过以下问题呢? new 和 delete 是函数吗? new [] 和 delete [] 又是什么?什么时候 ...

  2. [WCF编程]10.操作:回调操作

    一.回调操作概述 WCF支持服务将调用返回给它的客户端.在回调期间,许多方面都将颠倒过来:服务将成为客户端,客户端将编程服务.回调操作可以用在各种场景和应用程序中,但在涉及事件或者服务发生时间需要通知 ...

  3. 成功进行了一次UDP打洞

    本次测试参数:服务端是公网固定IP:两个客户端A和B分别位于不同电脑,不同宽带,不同型号路由后面(一个家庭路由,一个企业路由),且路由没有经过特别的设置.测试没有什么特别的地方,只是依照网络资料进行实 ...

  4. Spring学习3—控制反转(IOC)基于Annotation(注解)的依赖注入实现

    一.依赖注入--手工装配—注解方式 在java代码中使用@Autowired或@Resource注解方式进行装配的前提条件是:   1.引入context命名空间 需要在xml配置文件中配置以下信息: ...

  5. 测序深度和覆盖度(Sequencing depth and coverage)

    总是跑数据,却对数据一无所知,这说不过去吧. 看几篇文章吧 Sequencing depth and coverage: key considerations in genomic analyses( ...

  6. Android基础总结(1)

    1.Android开发的特点 四大组件:活动(Activity).服务(Service).广播接收器(Broadcast Receiver).内容提供器(Content Provider).其中活动是 ...

  7. Node.js基础学习三之登录功能

    本篇介绍Node.js访问数据库并返回数据给客户端 需求基于Node.js学习(二) 数据库请下载:user.sql 1.创建user 实体类(model-user.js) function User ...

  8. 吴恩达机器学习笔记38-决策下一步做什么(Deciding What to Do Next Revisited)

    我们已经讨论了模型选择问题,偏差和方差的问题.那么这些诊断法则怎样帮助我们判断,哪些方法可能有助于改进学习算法的效果,而哪些可能是徒劳的呢? 让我们再次回到最开始的例子,在那里寻找答案,这就是我们之前 ...

  9. 十一、移植优化---CONFIG 优化进 menuconfig(2)

    11.3 jz2440.h 中的剩余宏移植 11.3.1 CONFIG_SYS_TEXT_BASE CONFIG_SYS_TEXT_BASE:设置系统代码段的基地址,设为 0x0:menuconfig ...

  10. await异步的,容易理解一点

    C# 5.0中引入了async 和 await.这两个关键字可以让你更方便的写出异步代码. 看个例子: public class MyClass { public MyClass() { Displa ...