前言:

非常多非常多地方对于语句的优化,一般比較靠谱的回复即使——把运行计划发出来看看。当然那些仅仅看语句就说怎样怎样改代码,我一直都是拒绝的,由于这样的算是纯蒙。依据本人经验,大量的性能问题单纯从语句来看非常难发现瓶颈,同一个语句,由于环境的不同,差距非常大。所以比較合适的还是分析运行计划。

那么对于运行计划,一般使用图形化运行计划就差点儿相同了,可是用过的人也有一些疑惑,里面的图标(称为操作符)并不非常直观。

所以从本文開始,会整理一些不怎么常见但由比較重要的操作符并进行解释,对于那些表扫描、索引扫描、聚集索引扫描、索引查找、聚集索引查找这些非经常见的操作符,临时不打算介绍。

仅仅有了解一些重要且常见的操作符。才干对语句进行准确有效的性能分析和优化。

本系列文章预计包括以下操作符:

  1. 断言:Assert (英文版本号图形化界面的名字。中文版本号中XML格式的运行计划和TEXT格式的运行计划的名字。下同)
  2. 串联:Concatenation
  3. 计算标量:Compute Scalar
  4. 键查找:Key Lookup
  5. 假脱机:Spools
  6. 表假脱机:Lazy Spool
  7. 索引假脱机:Index Spool
  8. 行计数假脱机:Row CountSpool
  9. 流聚合:Stream Aggregate
  10. 排序:Sort
  11. 合并联接:Merge Join
  12. 合并间隔:Merge Interval
  13. 拆分、折叠:Split,Collapse

接下来从断言開始介绍。原文出处:http://blog.csdn.net/dba_huangzj/article/details/50261747

断言:

Assert运算符是一个物理运算符。

在运行计划中,假设为中文版图形化运行计划。被称为“断言”,在英文版及非图形化运行计划中显示为Assert。

其图标为:

Assert 运算符用于验证条件。

比如。验证引用完整性或确保标量子查询返回一行。

对于每一个输入行,Assert 运算符都要计算运行计划的 Argument 列中的表达式。

假设此表达式的值为 NULL。则通过 Assert 运算符传递该行,而且查询运行将继续。假设此表达式的值非空,则将产生对应的错误。

断言与Check约束:

先来看看这段代码,在server运行时。先创建測试环境。使用TempDB是不错的选择:

  1. USE tempdb
  2. GO
  3.  
  4. IF OBJECT_ID('TableAssert') IS NOT NULL
  5. DROP TABLE TableAssert
  6. GO
  7.  
  8. CREATE TABLE TableAssert (
  9. ID INTEGER
  10. ,Gender CHAR(1)
  11. )
  12. GO
  13.  
  14. ALTER TABLE TableAssert ADD CONSTRAINT ck_Gender_M_F CHECK (Gender IN ('M','F'))
  15. GO

选中以下代码。不要运行,选择“显示预计的运行计划”,如图:

代码例如以下:

  1. INSERT INTO TableAssert(ID ,Gender )
  2. VALUES (1,'X')
  3. GO

从上图可见有一个操作符叫“断言(Assert)”,那么这个里面是什么东西呢?把鼠标移到这个操作符上面能够看到下图:

注意上面的解释:用于验证指定的条件是否存在,这个解释非常直观。而且看谓词部分,说明了实际验证的内容。推断Gender字段的插入值是否属于F/M两种。假设不是则返回NULL。

断言操作符会针对验证返回值进行处理,假设验证返回NULL,则返回错误信息,也就是假设你直接运行INSERT语句就能够看到报错:

原文出处:http://blog.csdn.net/dba_huangzj/article/details/50261747

断言与外键约束:

以下来看个关于外键约束的样例:

  1. use tempdb
  2. go
  3. ALTER TABLE TableAssert ADD ID_Genders INT
  4. GO
  5. IF OBJECT_ID('TableFOREIGN') IS NOT NULL
  6. DROP TABLE TableFOREIGN
  7. GO
  8. CREATE TABLE TableFOREIGN(ID Integer PRIMARY KEY, Gender CHAR(1))
  9. GO
  10. INSERT INTO TableFOREIGN(ID, Gender) VALUES(1, 'F')
  11. INSERT INTO TableFOREIGN(ID, Gender) VALUES(2, 'M')
  12. INSERT INTO TableFOREIGN(ID, Gender) VALUES(3, 'N')
  13. GO
  14. ALTER TABLE TableAssert ADD CONSTRAINT fk_Tab2 FOREIGN KEY (ID_Genders) REFERENCES TableFOREIGN(ID)
  15. GO

相同,我们使用预计运行计划測试一下INSERT语句:

语句例如以下:

  1. INSERT INTO TableAssert(ID, ID_Genders, Gender) VALUES(1, 4, 'X')

这次我们使用另外一个工具:SET SHOWPLAN_TEXT ON 按这样的方式运行:

  1. SET SHOWPLAN_TEXT ON
  2. GO
  3. INSERT INTO TableAssert(ID, ID_Genders, Gender) VALUES(1, 4, 'X')

会看到两个结果,第一个是语句。不用关。我们看第二个结果:

  1. |--Assert(WHERE:(CASE WHEN NOT [Pass1009] AND [Expr1008] IS NULL THEN (0) ELSE NULL END))
  2. |--Nested Loops(Left Semi Join, PASSTHRU:([tempdb].[dbo].[TableAssert].[ID_Genders] IS NULL), OUTER REFERENCES:([tempdb].[dbo].[TableAssert].[ID_Genders]), DEFINE:([Expr1008] = [PROBE VALUE]))
  3. |--Assert(WHERE:(CASE WHEN [tempdb].[dbo].[TableAssert].[Gender]<>'F' AND [tempdb].[dbo].[TableAssert].[Gender]<>'M' THEN (0) ELSE NULL END))
  4. | |--Table Insert(OBJECT:([tempdb].[dbo].[TableAssert]), SET:([tempdb].[dbo].[TableAssert].[ID] = [@1],[tempdb].[dbo].[TableAssert].[ID_Genders] = [@2],[tempdb].[dbo].[TableAssert].[Gender] = [Expr1004]), DEFINE:([Expr1004]=CONVERT_IMPLICIT(char(1),[@3],0)))
  5. |--Clustered Index Seek(OBJECT:([tempdb].[dbo].[TableFOREIGN].[PK__TableFOR__3214EC27173876EA]), SEEK:([tempdb].[dbo].[TableFOREIGN].[ID]=[tempdb].[dbo].[TableAssert].[ID_Genders]) ORDERED FORWARD)

这个结果内容较多可能不直观。读者能够运行測试看结果。

能够看到里面有两次Assert,自下而上地阅读。第一个Assert(也就是以下那个,针对于图形化界面而言是右边那个,由于图形化运行计划是从右到左地阅读)是前面用于CHECK约束的,假设返回0则继续运行语句,否则返回错误。

对于第二个Assert用于检測两表关联的结果,当中“[Expr1008] IS NULL”(注意[Expr1008]不是固定的,依据每台机器可能返回不同值,在本人机器上的SQL 2008/2012分别运行都得到不同的[Expr]值)。我们须要知道[Expr1008]是什么。内容中有DEFINE:([Expr1008] = [PROBE VALUE]),这就是表关联的结果。

假设INSERT语句中ID_Gender的值已经存在与TableFOREIGN。那么这个Probe(探測器)会返回关联值。

否则返回NULL。所以这个“断言”是检查TableForeign中的值,假设没有找到INSERT中传入的值,断言会返回一个异常。

假设ID_Genders的值为NULL。那么SQL Server不能返回异常,而是返回“0”并继续运行语句。假设运行上面的INSERT语句。SQL Server会返回异常。由于值为’X’。违反了check约束:

可是假设把X换成F再运行,还是会报错。由于违反了外键约束:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

可是当把4换成NULL或1或2或3之后。再运行插入语句,就不会产生异常:

原文出处:http://blog.csdn.net/dba_huangzj/article/details/50261747

断言与子查询:

断言操作符相同能够用于检查子查询,对于标量子查询不能返回多个值,可是有时候写法和数据的变动会引发多值错误。此时断言扮演着校验标量子查询是否返回一个值的角色。

以下来看看这两个语句:

  1. INSERT INTO TableAssert(ID, Gender) VALUES((SELECT ID FROM TableAssert), 'F')
  2. INSERT INTO TableAssert(ID, Gender) VALUES((SELECT ID FROM TableAssert), 'F')

用上面的方法查看一下运行计划:

  1. SET SHOWPLAN_TEXT ON
  2. GO
  3. INSERT INTO TableAssert(ID,Gender) VALUES((SELECT ID FROM TableAssert), 'F')
  4. INSERT INTO TableAssert(ID,Gender) VALUES((SELECT ID FROM TableAssert), 'F')

观察语句大概能够知道发生什么情况。第一个insert会成功(除非你已经改动过里面的数据),由于VALUES中的SELECT部分仅仅返回一个值。可是第二个INSERT由于VALUES中的SELECT有两个值(第一个INSERT加入的),所以会报错。

结果例如以下:

  1. |--Assert(WHERE:([Expr1013]))
  2. |--Compute Scalar(DEFINE:([Expr1013]=CASE WHEN[tempdb].[dbo].[TableAssert].[Gender]<>'F' AND[tempdb].[dbo].[TableAssert].[Gender]<>'M' THEN (0) ELSE NULL END))
  3. |--Table Insert(OBJECT:([tempdb].[dbo].[TableAssert]),SET:([tempdb].[dbo].[TableAssert].[ID] =[Expr1009],[tempdb].[dbo].[TableAssert].[Gender] =[Expr1010],[tempdb].[dbo].[TableAssert].[ID_Genders] = NULL))
  4. |--Top(TOP EXPRESSION:((1)))
  5. |--ComputeScalar(DEFINE:([Expr1009]=[Expr1012], [Expr1010]='F'))
  6. |--Nested Loops(LeftOuter Join)
  7. |--ConstantScan
  8. |--Assert(WHERE:(CASE WHEN [Expr1011]>(1) THEN (0) ELSE NULL END))
  9. |--StreamAggregate(DEFINE:([Expr1011]=Count(*),[Expr1012]=ANY([tempdb].[dbo].[TableAssert].[ID])))
  10. |--Table Scan(OBJECT:([tempdb].[dbo].[TableAssert]))

注意最内层的Assert:

能够看到SQL Server创建一个StreamAggregate(流汇聚,可从预估运行计划中看到其解释。兴许会专门介绍)去计算子查询会返回多少数据。然后把这个值传递给断言用于检測。

作为已经商业化二十几年的产品,其核心(查询优化器)已经经过了非常多年的积累和改进,高版本号的SQL Server(如2008 R2及以上版本号。这个没有绝对标准),会对语句和表结构的当前情况来推断是否须要使用“断言,Assert”操作符。比方:

  1. INSERT INTO TableAssert(ID, Gender) VALUES((SELECT ID FROM TableAssert WHERE ID = 1), 'F')
  2. INSERT INTO TableAssert(ID, Gender) VALUES((SELECT TOP 1 ID FROM TableAssert), 'F')

原文出处:http://blog.csdn.net/dba_huangzj/article/details/50261747

先不运行,开启预计运行计划再看图形化界面,能够看到例如以下结果:

由于优化器检測到第二个语句里面包括了TOP 1,仅返回一行数据,所以没有必要引入断言来检測。

总结:

到这里为止。对这个操作符的介绍已经完毕,下一篇会介绍串联操作符。对于这个断言操作符。我们须要知道它是用来“验证”某些条件。可是每一个操作符的引入都必将带来一定的开销。可是这些操作符的引入又是必须的。由于须要它们完毕一些任务。

假设须要改进。最好还是先看看它是用来检验什么,比方上面提到的子查询。能够通过使用TOP 1、加入唯一约束等方式来降低这样的校验。

可是全部改进都应该做充分的測试和论证。

原文出处:http://blog.csdn.net/dba_huangzj/article/details/50261747

SQL Server 运行计划操作符具体解释(1)——断言(Assert)的更多相关文章

  1. SQL Server 运行计划操作符具体解释(2)——串联(Concatenation )

    本文接上文:SQL Server 运行计划操作符具体解释(1)--断言(Assert) 前言: 依据计划.本文開始讲述另外一个操作符串联(Concatenation).读者能够依据这个词(中英文均可) ...

  2. SQL Server 运行计划操作符具体解释(3)——计算标量(Compute Scalar)

    接上文:SQL Server 运行计划操作符详细解释(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介 ...

  3. SQL Server 执行计划操作符详解(3)——计算标量(Compute Scalar)

    接上文:SQL Server 执行计划操作符详解(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介绍第 ...

  4. SQL Server 执行计划操作符详解(2)——串联(Concatenation )

    本文接上文:SQL Server 执行计划操作符详解(1)--断言(Assert) 前言: 根据计划,本文开始讲述另外一个操作符串联(Concatenation),读者可以根据这个词(中英文均可)先幻 ...

  5. SQL Server 执行计划操作符详解(1)——断言(Assert)

    前言: 很多很多地方对于语句的优化,一般比较靠谱的回复即使--把执行计划发出来看看.当然那些只看语句就说如何如何改代码,我一直都是拒绝的,因为这种算是纯蒙.根据本人经验,大量的性能问题单纯从语句来看很 ...

  6. SQL Server 执行计划缓存

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/内存池/缓冲区 概述 了解执行计划对数据库性能分析很重要,其中涉及到了语句性能分析与存储,这也是写这篇文章的目的,在了解执行计划之 ...

  7. 微软官方提供的用于监控MS SQL Server运行状况的工具及SQL语句

    Microsoft SQL Server 2005 提供了一些工具来监控数据库.方法之一是动态管理视图.动态管理视图 (DMV) 和动态管理函数 (DMF) 返回的服务器状态信息可用于监控服务器实例的 ...

  8. Chapter 1 Securing Your Server and Network(1):选择SQL Server运行账号

    原文:Chapter 1 Securing Your Server and Network(1):选择SQL Server运行账号 原文出处:http://blog.csdn.net/dba_huan ...

  9. 引用:初探Sql Server 执行计划及Sql查询优化

    原文:引用:初探Sql Server 执行计划及Sql查询优化 初探Sql Server 执行计划及Sql查询优化 收藏 MSSQL优化之————探索MSSQL执行计划 作者:no_mIss 最近总想 ...

随机推荐

  1. ICMP协议和ping命令

    当网络不通的情况下,通常会想到ping命令,ping一下,但是ping命令内部如何执行的,可能并不清楚,其实ping是基于ICMP协议进行工作的.  一.ICMP协议的格式 ICMP是在RFC 792 ...

  2. pycharm debug后会出现 step over /step into/step into my code /force step into /step out 分别表示

    1.debug,全部打印 2.打断点debug,出现单步调试等按钮,只运行断点前 3.setup over 调试一行代码 4.setup out 运行断点后面所有代码 5.debug窗口显示调试按钮 ...

  3. (C/C++学习)17.bitset(位操作)

    说明:bitset 就像 vector 一样,是 C++ 的一个类模板库,用来对一个数的二进制位进行管理.判断等操作,使用时需要包含头文件 #include<bitset>. 1.声明及定 ...

  4. 关于C/C++的一些思考(1)

    C++的前世今生: C的结构化思想: Ada的模版思想: Fortran的运算符重载思想: Simula的OO思想:封装,继承,多态: C++类型描述了变量的三个特征: 该类型在内存中占用物理空间的大 ...

  5. HDFS的Java API 对文件的操作

    在本次操作中所用到的命令 1.首先启动HDFS $HADOOP_HOME/sbin/start-dfs.sh 2.关防火墙 切换到root用户,执行service iptables stop 3.拷贝 ...

  6. Java中Date类型的工具类

    package com.mytripod.util; import java.text.DateFormat; import java.text.SimpleDateFormat; import ja ...

  7. c++基础_杨辉三角形

    #include <iostream> using namespace std; int main(){ int n; cin>>n; ][]; ;i<n;i++){ a ...

  8. Spring Quartz 和 Spring Task使用比较

    Quartz 和 Spring Task执行时间对比: 1. Quartz同步模式:一个任务的两次执行的时间间隔是:“执行时间”和“trigger的设定间隔”的最大值 2. Task默认同步模式:一个 ...

  9. LeetCode 167. Two Sum II – Input array is sorted

    Given an array of integers that is already sorted in ascending order, find two numbers such that the ...

  10. [转]ionic或者angularjs中图片显示压缩问题解决 or 显示较大图片的某一块区域、裁剪显示

    我们知道在html中显示图片一般都是用img控件标签,当然调整大小的也很容易. 但是会出现,特定的img大小,显示一张比较大尺寸的且长宽比例与特定img大小不相符的图片.而导致压缩问题,图片挤压的很严 ...