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

本系列【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. 使用With递归查询 树

    UNION ALL -- 递归成员 SELECT a.* FROM tree a JOIN CTE c ON a.pid = c.id ) SELECT * from CTE   --1.将 CTE  ...

  2. eclipse使用lombok简化java代码

    可以利用注解来代替getter.setter.toString.hashCode.构造方法等,简化代码开发. 具体用法 https://www.cnblogs.com/qnight/p/8997493 ...

  3. Codeforces 1070J Streets and Avenues in Berhattan dp

    Streets and Avenues in Berhattan 我们首先能发现在最优情况下最多只有一种颜色会分别在行和列, 因为你把式子写出来是个二次函数, 在两端取极值. 然后我们就枚举哪个颜色会 ...

  4. python第十五天

    什么是模块? 一系列功能的集合 定义模块? 创建一个py文件就是一个模块,该py文件名就是模块名 怎么使用模块? 在要是用的模块文件中通过import 模块名 来导入模块 模块的四种方式? 1.编译执 ...

  5. UOJ#103. 【APIO2014】Palindromes PAM模板题

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ103.html 前言 我终于会PAM啦 感谢CLY大佬手把手教我PAM 题解 建个 PAM. 统计一下每一个节点的 Rig ...

  6. quartz之CronExpression表达式

    一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素.按顺序依次为1.秒(~).分钟(~).小时(~).天(月)(~,但是你需要考虑你月的天数).月(~).天(星期)(~ =SUN 或 SU ...

  7. KaliLinuxNetHunter教程刷入第三方Recovery与开始刷机

    KaliLinuxNetHunter教程刷入第三方Recovery与开始刷机 2.刷入第三方Recovery(即TWRP) TWRP(TeamWin Recovery Project)是一款XDA大神 ...

  8. 解释器、环境变量、如何运行python程序、变量先定义后引用

    python解释器的介绍.解释器的安装.环境变量的添加为什么加环境变量.如何调取不同的解释器版本实现多版本共存.python程序如何运行的.python的变量定义 一.python解释器: 用来翻译语 ...

  9. 如何使用 tf object detection

    # 如何使用 tf object detection https://juejin.i m/entry/5a7976166fb9a06335319080 https://towardsdatascie ...

  10. javascript 数据类型 -- 分类

    一.概念 Javascript 中有6中基本类型(也称 原始类型/原始值): number . sring . boolean . symbol . undefined 和 null ,和1种引用类型 ...