1. Execution Plan查询计划展示了SQL Server试图如何执行查询以及实际上是如何执行查询的;查询计划最佳使用方法不是查看一个查询计划,解决查询中性能最坏的地方,而是你认为SQL Server会如何执行你查询,并通过查询计划验证SQL Server是否按照你设想执行了查询计划
  1. 查询执行过程:
  • T-SQL解析,检查查询的语句是否符合语法
  • 对象名称确定,确定查询中对象名称指的是哪个底层对象
  • 查询优化,根据可用的统计信息,决定如何执行查询;不一定使用可能的最佳的查询计划,其目的是在合理的时间范围内使用满意的查询计划,因为寻找最佳的查询计划可能会消耗更多的时间,查询越复杂,需要评估查询计划的时间越长;不需要考虑DDL语句的可选执行计划,许多简单的查询的执行计划也是很trival的,因为他们的执行计划可以很快的确定
  • 执行查询计划,一旦确定查询计划,执行引擎和查询引擎开始执行查询计划,可能会抛出运行时异常
  • 缓存查询计划,如果查询计划被认为使用的很高效,它会被存储到查询计划缓存中,稍后会重用缓存中的查询计划;不过对于有些查询来说,总是不缓存
  1. 查询计划决定执行操作类型,操作执行的顺序,是否使用索引,估计的行数,这些决定都是基于当时可用的统计信息;SQL Server使用基于cost的优化器,查询计划中每个元素都被赋予一个cost,用来决定一个操作是否比其他操作更便宜或者昂贵
  2. 评估的查询计划在调试查询时非常有用;不是每次都能够检索到查询计划,一个原因就是在批处理中创建了对象,然后访问他们,对象还不存在,SQL Server没有他们的信息,就不能创建处理他们的评估查询计划;实际查询计划和评估查询计划可能是不同的,因为两个时机可用资源是不一样的;查询计划包含了每个数据路径中的数据行数,对于评估查询计划这是基于可用的统计信息的,对于实际查询计划,评估的和实际的行数都会展示出来
  3. 多个用户可以同时执行同样的查询计划,每个用户都需要和自己查询计划执行相关的单独的数据,保存这些数据的对象就称为Execution Context;执行上下文和查询计划采用相似的缓存方式,当执行查询计划时,如果有的话就从缓存中检索执行上下文;出于性能和内存需求考虑,执行上下文不是完整的,带有分支的代码会被剔除掉,这样导致带有分支(IF语句)存储过程从缓存中检索出的上下文可能是不一致的,因为可能存在两个存储过程去除分支语句后上下文是一致的情况,但是这两个存储过程的上下文显然应该是不一样的;这里也看出,从缓存角度讲,在存储过程中应该避免过多的过程式逻辑,相反应该优先采用基于集合的逻辑
  4. 查询计划的格式:
  • 基于文本的查询计划,已经被基于XML的查询计划所替代,通过设置SET SHOWPLAN_TEXT ON,查询该形式的查询计划
  • 基于XML的查询计划,SSMS将查询计划保存为.sqlplan后缀的文件(其实就是XML文件),便于移植(即可以发送到别的机器上),便于编程(因为XML的通用性)
  • 可视化的查询计划:查看查询计划更加容易,没有包含XML形式查询计划的所有信息,这些额外的信息只能通过读取XML文件获得
  1. 表扫描和聚集索引扫描本质上是一样的,只不过一个在堆上扫描,一个在建了聚集索引的表上扫描,只有聚集索引Seek效率非常高,直接定位到特定行
  2. Nested Loops用来实现Inner Join操作,共有两个数据路径,首先是Index Seek,然后是RID Lookup或者Key Lookup,取决于表是否建了聚集索引,Lookup操作通常都是很昂贵的操作,因为需要对Index Seek到的每行执行这样的操作,适合于第一个操作的表数据行比较小的情形
  3. Merge JoinHash Join是另外一种形式的Join操作,Merge Join更加高效,但是需要排序
  • Merge Join:在两个表按照连接列排好序以后,按照ID逐个进行Merge
  • Hash Join:先根据一个表,对连接列计算哈希值,构建一张哈希表,另一张表使用同样的算法为每一行计算哈希值,查找该行属于哈希表中哪一行,和属于的这一行进行合并;该操作的出现通常说明底层表缺乏合适的索引
  1. Stream Aggregate类似于Merge Join,先将两张表按照同一列进行排序,然后进行聚合;Hash Match Aggregate类似于Hash Join,根据哈希算法进行合并,然后在进行聚合,该操作的出现同样说明底层表缺乏合适的索引
  1. Filter操作主要是用于Where或者Having语句,低成本的操作,仅仅让满足过滤条件的数据行通过;Sort操作通常是用于ORDER BY语句,但是也用于其他语句,比如DISTINCTUNION,这是非常昂贵的操作,避免不必要的排序
  1. 可以通过组合插入、更新、删除操作来实现T-SQLMERGE语句,这些操作可能还会涉及到其他操作,比如在插入时可能涉及到查询操作
  2. 捕获查询计划的方法:
  • SSMSVS2010
  • SQL Profiler:有一个事件Performance > Showplan XML将查询计划包含在trace中,需要注意的是添加该trace后,会产生大量的输出,系统性能会下降
  • Dynamic Management Views(DMVs):提供关于最近执行耗时和没有使用索引的查询(sys.dm_exec_cached_plans)
  • Activity Monitor:也可以展示DMVs查询的结果
  • SQL Server Data Collection:收集来自DMVs的信息,将它上传到中心数据库,提供一系列基于这些数据的报表,和Activity Monitor不同的是它会收集历史数据
  1. 通常来说重用查询计划都是合意的,有些情况例外,比如parameter sniffing,即使用不用的参数集合
  2. SQL Server基于以下两个因素决定是否将查询计划从缓存中剔除:
  • 正确性,比如SET选项的修改,SCHEMA修改都会影响正确性
  • 最优性,数据被修改足够多的情况下就要考虑重新生成查询计划
  1. SQL Server为每个缓存的查询计划都赋予一个cost,用来衡量重新生成查询计划的成本;当内存资源非常紧张的时候,SQL Server需要决定哪些查询计划最应该被保留,基于该查询计划的cost和最近是否被重用;可以强制重新生成查询计划(sp_recompile,WITH RECOMPILE)
  2. DMVs不是持久化的,数据库服务器重启会被重置(有的重置的更加频繁),和查询计划相关的DMVs如下:
  • sys.dm_exec_connections:一行是一个用户对服务器的连接
  • sys.dm_exec_sessions:每个会话一行,包括系统会话和用户会话
  • sys.dm_exec_query_stats:查询统计信息
  • sys.dm_exec_requests:会话相关,为每个当前执行的请求提供一行
  • sys.dm_exec_sql_text():查询一次请求中执行的T-SQL代码的能力
  • sys.dm_exec_query_plan():提供查询一次请求的执行计划的能力
  • sys.dm_exec_cached_plans:缓存的查询计划的细节
  • sys.dm_exec_cached_plan_dependent_objects():缓存查询计划依赖的对象细节信息