听到大牛们说执行计划,总是很惶恐,是对知识的缺乏的惶恐,所以必须得学习执行计划,以减少对这一块知识的惶恐,下面是对执行计划的第一讲-理解执行计划。

本系列【T-SQL】主要是针对T-SQL的总结。

一、为什么需要执行计划?

(1)帮助分析

当我们想要去分析SQL语句存在很慢时,需要有一个分析工具帮助我们分析SQL语句中哪些地方存在性能问题,而这个分析工具就是执行计划,看懂执行计划就能知道哪些地方有性能问题,然后结合自己已有的SQL知识分析为什么这些地方有性能问题,进而尝试提出解决方案,并测试自己的方案是否能提高性能,以及方案是否合理。

(2)获取其他信息

a.哪些索引被用在查询中

b.数据是怎样关联起来的

c.数据是怎样检索的

d.为什么SQL Server没有使用这些索引

e.SQL语句的执行顺序

二、什么是执行计划?

SQL语句执行之前,需要有一个执行的方案,而这个方案是由查询优化器(查询分析器)产生的,并且是高效的、开销最小的方案,这就是执行计划。不知道查询优化器的可以看我写之前写的一篇博客:

【T-SQL进阶】02.理解SQL查询的底层原理

三、如何显示执行计划?

执行计划有三种格式:图形化执行计划,文本化执行计划,XML格式的执行计划。

(1)图形化执行计划

优点:可视性好。

a.估计的执行计划

可以通过鼠标点击图标显示估计的执行计划或者通过快捷键Ctrl+L显示估计执行计划。预估执行计划不会真正执行,只是预估出来的执行计划。

b.实际的执行计划

单击实际的执行计划图标,该图标处于选中状态,然后执行SQL语句,将会显示实际执行的执行计划。

(2)文本化执行计划

用独立的行来代表每一个迭代器。使用竖线(符号“|”)来代表查询树中迭代器之间的父子关系。数据都是从子迭代器流向父迭代器。

优点:和图形计划比较,文本执行计划更容易保存、处理、搜索和比较。

--显示完整的预估执行计划信息
SET SHOWPLAN_TEXT ON
GO
--显示预估执行计划的有限信息,可以用osql.exe等工具分析
SET SHOWPLAN_ALL ON
GO
--显示完整的实际执行计划信息
SET STATISTICS PROFILE ON
GO

总结:

(3)XML执行计划

优点:三种执行计划中最详细的。图形执行计划可以保存为扩展名为.sqlplan的XML格式的计划文件,打开此文件将会以图形化的执行计划展示。

--显示预估执行计划
SET SHOWPLAN_XML ON
GO
--显示实际计划的XML格式数据
SET STATISTICS XML ON
GO

总结

四、如何分析执行计划?

下面分析三种情况的执行计划:

1.堆表

2.聚集索引

3.非聚集索引

结构 扫描 查找 书签查找
堆表 表扫描 没有这种情况 RID 查找
聚集索引 聚集索引扫描 聚集索引查找 没有这种情况
非聚集索引 如果用到了索引,则是索引扫描 索引查找 Key 查找

关于表扫描的那些事:

  • 没有索引的表称作堆表,查找匹配行用的是表扫描。
  • 如果出现表扫描操作,则证明这个表上一定没有聚集索引。

关于索引查找的那些事:

假设[列1]上有一个单列索引,可以使用这个索引查找下面这些谓词:

1.[列1] = 1.23

2.[列1] > 1.23

3.[列1] BETWEEN 1 AND 100

4.[列1] LIKE 'abc%'

5.[列1] IN (1,3,7,10)

  不能使用这个索引对下列这些谓词进行查找:

1.ABS[列1] = 1

2.[列1] + 10 > 12

3.[列1] LIKE '%abc'

关于非聚集索引的那些事:

  1. 如果只有非聚集索引时,非聚集索引不包含查询列时,则SQL查询优化器选择非聚集索引扫描。
  2. 只有非聚集索引时,非聚集索引不包含过滤条件列时,则选择表扫描。
  3. 非聚集索引具有独立于数据行的结构。 非聚集索引包含非聚集索引键值,并且每个键值项都有指向包含该键值的数据行的指针。
  4. 从非聚集索引中的索引行指向数据行的指针称为行定位器。 行定位器的结构取决于数据页是存储在堆中还是聚集表中。 对于堆,行定位器是指向行的指针。 对于聚集表,行定位器是聚集索引键。
  5. 您可以向非聚集索引的叶级添加非键列(包含列)以跳过现有的索引键限制(900 字节和 16 键列),并执行完整范围内的索引查询。

关于聚集索引的那些事:

1. 如果表上有聚集索引,则扫描称作聚集索引扫描,查找称作聚集索引查找;

2. 聚集索引扫描和表扫描的性能没多大差异;

3.聚集索引根据数据行的键值在表或视图中排序和存储这些数据行。

4.索引定义中包含聚集索引列。

5.每个表只能有一个聚集索引,因为数据行本身只能按一个顺序排序。

6.只有当表包含聚集索引时,表中的数据行才按排序顺序存储。 如果表具有聚集索引,则该表称为聚集表。如果表没有聚集索引,则其数据行存储在一个称为堆的无序结构中。

7.加了聚集索引不一定能提高性能,有些情况下,性能可能不如表扫描;

8.聚集索引就是表本身。表有多少行和多少列,聚集索引就有多少行和和多少列。

9.单表查询中,过滤条件中有聚集索引列,且能用这个索引查找过滤条件中的谓词,则是聚集索引查找,过滤条件中没有聚集索引列则是聚集索引扫描。

(1)没有索引的情况

创建myOrder表

USE [Test]
GO
 
CREATE TABLE [dbo].[myOrder](
[id] [int] NOT NULL,
[customer] [nvarchar](100) NOT NULL
) ON [PRIMARY]
 
GO

myOrder只有两列id,customer,这两列上面都没有索引。

SELECT [id]
FROM [Test].[dbo].[myOrder]
WHERE [customer] = 'ddd'

下面是执行计划:

customer列上面没有索引,SQL Server需要读取myOrder表的每一行来判断customer='ddd',如果结果为true,则返回此行。

查询的示例图如下,customer=ddd 存在三条记录。

注意:

1.扫描及查找是SQL Server用来从表和索引中读取数据的迭代器;

2.扫描用来处理整个表或索引的全部分支;

3.查找是在谓词基础上有效返回索引中一个或多个范围中的行。

(2)有非聚集索引的情况

在id上创建非聚集索引

USE [Test]
GO
 
--删除索引dbo.myOrder.ID_NON_INDEX
DROP INDEX dbo.myOrder.ID_NON_INDEX
 
CREATE NONCLUSTERED INDEX [ID_NON_INDEX] ON [dbo].[myOrder]
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

1.查询条件的列上没有非聚集索引,查询列上没有非聚集索引->表扫描

--id列上有索引,customer列上没有索引,查询条件中用的是customer='ddd'进行过滤。
--由于customer列上没有索引,所以需要进行表扫描来找到符合customer='ddd'的行。
SELECT [id]
FROM [Test].[dbo].[myOrder]
WHERE [customer] = 'ddd' SELECT [customer]
FROM [Test].[dbo].[myOrder]
WHERE [customer] = 'ddd' SELECT [id],[customer]
FROM [Test].[dbo].[myOrder]
WHERE [customer] = 'ddd' SELECT [id]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2 AND [customer] ='ddd' SELECT [id],[customer]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2 AND [customer] ='ddd'

2.查询条件的列上有非聚集索引,查询列上没有非聚集索引->表扫描

--id列上有索引,customer列上没有索引,查询条件中用的是id=2进行过滤。
--SELECT查询需要返回customer列,由于customer列上没有索引,且索引[ID_NON_INDEX]不包含customer列,
--即使用非聚集索引扫描找到了符合过滤条件id=2的索引分支,但是只能在该索引分支上面拿到id列的值,因为该索引分支只包含了id列,其他列的值拿不到。
--所以还是需要进行表扫描来找到符合条件的行,然后获取该行的customer列的值。
--这里有个疑问:为什么找到索引分支后,不能继续找到对应的行,然后拿到这行的customer列??
SELECT [customer]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2 SELECT [id],[customer]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2

3.查询条件的列上有非聚集索引,查询列上有非聚集索引->索引查找

--id列上有索引,customer列上没有索引,查询条件中用的是id=2进行过滤。
--SELECT查询需要返回id列,使用非聚集索引扫描找到了符合过滤条件id=2的索引分支,在找到的索引分支上拿到id列的值。
SELECT [id]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2

(3)有聚集索引的情况

1.查询条件的列上没有聚集索引->聚集索引扫描

--
--id列上有聚集索引,customer列上没有索引,查询条件中用的是customer='ddd'进行过滤。
--由于customer列上没有索引,所以需要进行扫描来找到符合customer='ddd'的行。
--只要有聚集索引,则扫描就是聚集索引扫描。聚集索引和表扫描的性能基本上一样。
SELECT [id]
FROM [Test].[dbo].[myOrder]
WHERE [customer] = 'ddd' SELECT [customer]
FROM [Test].[dbo].[myOrder]
WHERE [customer] = 'ddd' SELECT [id],[customer]
FROM [Test].[dbo].[myOrder]
WHERE [customer] = 'ddd'

  

2.查询条件的列上有聚集索引->聚集索引查找

--id列上有索引,customer列上没有索引,查询条件中用的是id=2进行过滤。
--用聚集索引查找到了id=2的行,由于表中的行就是按照id列来排序的,所以找到了这一行,
--也就能找到这一行的所有列,所以能够拿到customer列。所以是聚集索引扫描。
SELECT [customer]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2 SELECT [id]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2 SELECT [id],[customer]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2

  

3.查询条件中,有一列有聚集索引,另一列没有聚集索引->聚集索引查找

--id列上有索引,customer列上没有索引,查询条件中用的是[id] = 2,[customer] ='ddd'进行过滤。
--当过滤条件中有一个可以根据聚集索引来查找时,先用聚集索引来找到匹配的行([id] = 2),然后再在过滤出来的行中筛选处符合[customer] ='ddd'的行。
--所以是聚集索引查找。
--疑问:为什么第二步筛选操作在执行计划图中没有体现??这个地方我想到的是拿到id=2的匹配行后,直接舍弃掉不符合条件[customer] ='ddd'的行,这个舍弃动作就没有直接体现出来。
SELECT [id]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2 AND [customer] ='ddd' SELECT [id],[customer]
FROM [Test].[dbo].[myOrder]
WHERE [id] = 2 AND [customer] ='ddd' SELECT [id],[customer]
FROM [Test].[dbo].[myOrder]
WHERE [customer] ='3333' AND [id] = 2

  

->>【T-SQL】系列文章全文目录(2017-06-26更新)

作  者:
Jackson0714

出  处:http://www.cnblogs.com/jackson0714/

关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教!

版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我

声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!

【SQL进阶】03.执行计划之旅1 - 初探的更多相关文章

  1. 【T-SQL进阶】03.执行计划之旅-1

    到大牛们说执行计划,总是很惶恐,是对知识的缺乏的惶恐,所以必须得学习执行计划,以减少对这一块知识的惶恐,下面是对执行计划的第一讲-理解执行计划. 本系列[T-SQL]主要是针对T-SQL的总结. T- ...

  2. SQL Server 优化-执行计划

    对于SQL Server的优化来说,优化查询可能是很常见的事情.由于数据库的优化,本身也是一个涉及面比较的广的话题, 因此本文只谈优化查询时如何看懂SQL Server查询计划.毕竟我对SQL Ser ...

  3. 了解Sql Server的执行计划

    前一篇总结了Sql Server Profiler,它主要用来监控数据库,并跟踪生成的sql语句.但是只拿到生成的sql语句没有什么用,我们可以利用这些sql语句,然后结合执行计划来分析sql语句的性 ...

  4. 【MS SQL】通过执行计划来分析SQL性能

    原文:[MS SQL]通过执行计划来分析SQL性能 如何知道一句SQL语句的执行效率呢,只知道下面3种: 1.通过SQL语句执行时磁盘的活动量(IO)信息来分析:SET STATISTICS IO O ...

  5. SQL Server实际执行计划COST"欺骗"案例

    有个系统,昨天Support人员发布了相关升级脚本后,今天发现系统中有个功能不能正常使用了,直接报超时了(Timeout expired)的错误.定位到相关相关存储过程后,然后在优化分析的过程中,又遇 ...

  6. 官方文档:11G新特性SQL PLAN BASLINE 执行计划基线

    什么是SQL执行计划管理? SQL计划管理(SQL plan management)是一咱预防机制,记录和评估SQL语句的执行计划.SQL plan management的主要功能是sql plan ...

  7. oracle中查看sql语句的执行计划

    1.在pl/sql中打开cmd命令容器 2.在cmd命令窗口中输入:explain plan for select * from t; 3.查看sql语句的执行计划:select * from tab ...

  8. 程序员眼中的 SQL Server-执行计划教会我如何创建索引?

    先说点废话 以前有 DBA 在身边的时候,从来不曾考虑过数据库性能的问题,但是,当一个应用程序从头到脚都由自己完成,而且数据库面对的是接近百万的数据,看着一个页面加载速度像乌龟一样,自己心里真是有种挫 ...

  9. SQL SERVER 2012 执行计划走嵌套循环导致性能问题的案例

    开发人员遇到一个及其诡异的的SQL性能问题,这段完整SQL语句如下所示: declare @UserId             INT declare @PSANo              VAR ...

随机推荐

  1. 自己动手写Redis客户端- Redis协议(1)

    网络层 客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 . 客户端和服务器发送的命令或数据一律以 \r\n (CRLF)结尾. 请求 Redis 服务器接受命令以及命 ...

  2. UOJ#416. 【APIO2018】铁人两项

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ416.html 前言 完了完了SB选手Tarjan写挂. 题解 考虑先Tarjan缩个点双建个圆方树. 然后发现,确定起点 ...

  3. 部分手机浏览器存在将ajax请求当成广告过滤的情况,及解决方案

    我们发现h5页面在某些浏览器请求不到数据,经过排查,是浏览器的广告拦截模块搞的鬼. 通过删减参数,发现adtype和adnum参数去掉后,接口可以正常请求,开始以为是官方拦截关键词带有ad的参数,后来 ...

  4. 指针*p,p,&p等辨别

    #include<iostream> #include<iomanip> #include<cmath> using namespace std; int main ...

  5. 小程序app.onLaunch中获取用户信息,index.onLoad初次载入时取不到值的问题

    问题描述: //app.js App({ globalData:{ nickname:'' }, onLaunch: function () { let that=this; //假设已经授权成功 w ...

  6. 本机是wifi,虚拟机无法连接外网问题

    1.首先看自己本机的各网口是否都启动. 2.在虚拟机中的虚拟网络编辑器中,选择桥接模式,并选择对应第一步的WLAN端口. 3.在虚拟机设置中选择自定义,选择第二部中选的VMnet2即可上网了.

  7. margin-top的兼容问题

    产生的条件:子元素给了margin-top,并且父元素没有浮也没有其他样式,浏览器解析的结果是父元素下去了. 解决方法:1.给子元素或者父元素添加浮动,缺点:如果不需要浮动,添加浮动也页面布局会乱 2 ...

  8. VB用API模拟截屏键PrintScreen

    很多人用 SendKeys "{PRTSC}" 模拟截屏键 PrintScreen 的时候提示<错误:'70' 拒绝的权限>,于是经常遇到人问...干脆写下来 '声明 ...

  9. [转].Net-C#的委托(代理)和事件

    一.代理 首先我们要弄清代理是个什么东西.别让一串翻译过来的概念把大家搞晕了头.有的文章把代理称委托.代表等,其实它们是一个东西,英文表述都是“Delegate”.由于没有一本权威的书来规范这个概念, ...

  10. python学习笔记(7)

    第七章 文件和数据格式化 文件的使用 文件是数据的抽象和集合 文件是存储在辅助存储器上的数据序列 文件是数据存储的一种形式 文件展现形态:文本文件和二进制文件 文本文件 由单一特定编码组成的文件,如U ...