SQL Server 运行计划操作符具体解释(1)——断言(Assert)
前言:
非常多非常多地方对于语句的优化,一般比較靠谱的回复即使——把运行计划发出来看看。当然那些仅仅看语句就说怎样怎样改代码,我一直都是拒绝的,由于这样的算是纯蒙。依据本人经验,大量的性能问题单纯从语句来看非常难发现瓶颈,同一个语句,由于环境的不同,差距非常大。所以比較合适的还是分析运行计划。
那么对于运行计划,一般使用图形化运行计划就差点儿相同了,可是用过的人也有一些疑惑,里面的图标(称为操作符)并不非常直观。
所以从本文開始,会整理一些不怎么常见但由比較重要的操作符并进行解释,对于那些表扫描、索引扫描、聚集索引扫描、索引查找、聚集索引查找这些非经常见的操作符,临时不打算介绍。
仅仅有了解一些重要且常见的操作符。才干对语句进行准确有效的性能分析和优化。
本系列文章预计包括以下操作符:
- 断言:Assert (英文版本号图形化界面的名字。中文版本号中XML格式的运行计划和TEXT格式的运行计划的名字。下同)
- 串联:Concatenation
- 计算标量:Compute Scalar
- 键查找:Key Lookup
- 假脱机:Spools
- 表假脱机:Lazy Spool
- 索引假脱机:Index Spool
- 行计数假脱机:Row CountSpool
- 流聚合:Stream Aggregate
- 排序:Sort
- 合并联接:Merge Join
- 合并间隔:Merge Interval
- 拆分、折叠:Split,Collapse
接下来从断言開始介绍。原文出处:http://blog.csdn.net/dba_huangzj/article/details/50261747
断言:
Assert运算符是一个物理运算符。
在运行计划中,假设为中文版图形化运行计划。被称为“断言”,在英文版及非图形化运行计划中显示为Assert。
其图标为:
Assert 运算符用于验证条件。
比如。验证引用完整性或确保标量子查询返回一行。
对于每一个输入行,Assert 运算符都要计算运行计划的 Argument 列中的表达式。
假设此表达式的值为 NULL。则通过 Assert 运算符传递该行,而且查询运行将继续。假设此表达式的值非空,则将产生对应的错误。
断言与Check约束:
先来看看这段代码,在server运行时。先创建測试环境。使用TempDB是不错的选择:
- USE tempdb
- GO
- IF OBJECT_ID('TableAssert') IS NOT NULL
- DROP TABLE TableAssert
- GO
- CREATE TABLE TableAssert (
- ID INTEGER
- ,Gender CHAR(1)
- )
- GO
- ALTER TABLE TableAssert ADD CONSTRAINT ck_Gender_M_F CHECK (Gender IN ('M','F'))
- GO
选中以下代码。不要运行,选择“显示预计的运行计划”,如图:
代码例如以下:
- INSERT INTO TableAssert(ID ,Gender )
- VALUES (1,'X')
- GO
从上图可见有一个操作符叫“断言(Assert)”,那么这个里面是什么东西呢?把鼠标移到这个操作符上面能够看到下图:
注意上面的解释:用于验证指定的条件是否存在,这个解释非常直观。而且看谓词部分,说明了实际验证的内容。推断Gender字段的插入值是否属于F/M两种。假设不是则返回NULL。
断言操作符会针对验证返回值进行处理,假设验证返回NULL,则返回错误信息,也就是假设你直接运行INSERT语句就能够看到报错:
原文出处:http://blog.csdn.net/dba_huangzj/article/details/50261747
断言与外键约束:
以下来看个关于外键约束的样例:
- use tempdb
- go
- ALTER TABLE TableAssert ADD ID_Genders INT
- GO
- IF OBJECT_ID('TableFOREIGN') IS NOT NULL
- DROP TABLE TableFOREIGN
- GO
- CREATE TABLE TableFOREIGN(ID Integer PRIMARY KEY, Gender CHAR(1))
- GO
- INSERT INTO TableFOREIGN(ID, Gender) VALUES(1, 'F')
- INSERT INTO TableFOREIGN(ID, Gender) VALUES(2, 'M')
- INSERT INTO TableFOREIGN(ID, Gender) VALUES(3, 'N')
- GO
- ALTER TABLE TableAssert ADD CONSTRAINT fk_Tab2 FOREIGN KEY (ID_Genders) REFERENCES TableFOREIGN(ID)
- GO
相同,我们使用预计运行计划測试一下INSERT语句:
语句例如以下:
- INSERT INTO TableAssert(ID, ID_Genders, Gender) VALUES(1, 4, 'X')
这次我们使用另外一个工具:SET SHOWPLAN_TEXT ON 按这样的方式运行:
- SET SHOWPLAN_TEXT ON
- GO
- INSERT INTO TableAssert(ID, ID_Genders, Gender) VALUES(1, 4, 'X')
会看到两个结果,第一个是语句。不用关。我们看第二个结果:
- |--Assert(WHERE:(CASE WHEN NOT [Pass1009] AND [Expr1008] IS NULL THEN (0) ELSE NULL END))
- |--Nested Loops(Left Semi Join, PASSTHRU:([tempdb].[dbo].[TableAssert].[ID_Genders] IS NULL), OUTER REFERENCES:([tempdb].[dbo].[TableAssert].[ID_Genders]), DEFINE:([Expr1008] = [PROBE VALUE]))
- |--Assert(WHERE:(CASE WHEN [tempdb].[dbo].[TableAssert].[Gender]<>'F' AND [tempdb].[dbo].[TableAssert].[Gender]<>'M' THEN (0) ELSE NULL END))
- | |--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)))
- |--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
断言与子查询:
断言操作符相同能够用于检查子查询,对于标量子查询不能返回多个值,可是有时候写法和数据的变动会引发多值错误。此时断言扮演着校验标量子查询是否返回一个值的角色。
以下来看看这两个语句:
- INSERT INTO TableAssert(ID, Gender) VALUES((SELECT ID FROM TableAssert), 'F')
- INSERT INTO TableAssert(ID, Gender) VALUES((SELECT ID FROM TableAssert), 'F')
用上面的方法查看一下运行计划:
- SET SHOWPLAN_TEXT ON
- GO
- INSERT INTO TableAssert(ID,Gender) VALUES((SELECT ID FROM TableAssert), 'F')
- INSERT INTO TableAssert(ID,Gender) VALUES((SELECT ID FROM TableAssert), 'F')
观察语句大概能够知道发生什么情况。第一个insert会成功(除非你已经改动过里面的数据),由于VALUES中的SELECT部分仅仅返回一个值。可是第二个INSERT由于VALUES中的SELECT有两个值(第一个INSERT加入的),所以会报错。
结果例如以下:
- |--Assert(WHERE:([Expr1013]))
- |--Compute Scalar(DEFINE:([Expr1013]=CASE WHEN[tempdb].[dbo].[TableAssert].[Gender]<>'F' AND[tempdb].[dbo].[TableAssert].[Gender]<>'M' THEN (0) ELSE NULL END))
- |--Table Insert(OBJECT:([tempdb].[dbo].[TableAssert]),SET:([tempdb].[dbo].[TableAssert].[ID] =[Expr1009],[tempdb].[dbo].[TableAssert].[Gender] =[Expr1010],[tempdb].[dbo].[TableAssert].[ID_Genders] = NULL))
- |--Top(TOP EXPRESSION:((1)))
- |--ComputeScalar(DEFINE:([Expr1009]=[Expr1012], [Expr1010]='F'))
- |--Nested Loops(LeftOuter Join)
- |--ConstantScan
- |--Assert(WHERE:(CASE WHEN [Expr1011]>(1) THEN (0) ELSE NULL END))
- |--StreamAggregate(DEFINE:([Expr1011]=Count(*),[Expr1012]=ANY([tempdb].[dbo].[TableAssert].[ID])))
- |--Table Scan(OBJECT:([tempdb].[dbo].[TableAssert]))
注意最内层的Assert:
能够看到SQL Server创建一个StreamAggregate(流汇聚,可从预估运行计划中看到其解释。兴许会专门介绍)去计算子查询会返回多少数据。然后把这个值传递给断言用于检測。
作为已经商业化二十几年的产品,其核心(查询优化器)已经经过了非常多年的积累和改进,高版本号的SQL Server(如2008 R2及以上版本号。这个没有绝对标准),会对语句和表结构的当前情况来推断是否须要使用“断言,Assert”操作符。比方:
- INSERT INTO TableAssert(ID, Gender) VALUES((SELECT ID FROM TableAssert WHERE ID = 1), 'F')
- 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)的更多相关文章
- SQL Server 运行计划操作符具体解释(2)——串联(Concatenation )
本文接上文:SQL Server 运行计划操作符具体解释(1)--断言(Assert) 前言: 依据计划.本文開始讲述另外一个操作符串联(Concatenation).读者能够依据这个词(中英文均可) ...
- SQL Server 运行计划操作符具体解释(3)——计算标量(Compute Scalar)
接上文:SQL Server 运行计划操作符详细解释(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介 ...
- SQL Server 执行计划操作符详解(3)——计算标量(Compute Scalar)
接上文:SQL Server 执行计划操作符详解(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介绍第 ...
- SQL Server 执行计划操作符详解(2)——串联(Concatenation )
本文接上文:SQL Server 执行计划操作符详解(1)--断言(Assert) 前言: 根据计划,本文开始讲述另外一个操作符串联(Concatenation),读者可以根据这个词(中英文均可)先幻 ...
- SQL Server 执行计划操作符详解(1)——断言(Assert)
前言: 很多很多地方对于语句的优化,一般比较靠谱的回复即使--把执行计划发出来看看.当然那些只看语句就说如何如何改代码,我一直都是拒绝的,因为这种算是纯蒙.根据本人经验,大量的性能问题单纯从语句来看很 ...
- SQL Server 执行计划缓存
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/内存池/缓冲区 概述 了解执行计划对数据库性能分析很重要,其中涉及到了语句性能分析与存储,这也是写这篇文章的目的,在了解执行计划之 ...
- 微软官方提供的用于监控MS SQL Server运行状况的工具及SQL语句
Microsoft SQL Server 2005 提供了一些工具来监控数据库.方法之一是动态管理视图.动态管理视图 (DMV) 和动态管理函数 (DMF) 返回的服务器状态信息可用于监控服务器实例的 ...
- 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 ...
- 引用:初探Sql Server 执行计划及Sql查询优化
原文:引用:初探Sql Server 执行计划及Sql查询优化 初探Sql Server 执行计划及Sql查询优化 收藏 MSSQL优化之————探索MSSQL执行计划 作者:no_mIss 最近总想 ...
随机推荐
- ICMP协议和ping命令
当网络不通的情况下,通常会想到ping命令,ping一下,但是ping命令内部如何执行的,可能并不清楚,其实ping是基于ICMP协议进行工作的. 一.ICMP协议的格式 ICMP是在RFC 792 ...
- 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窗口显示调试按钮 ...
- (C/C++学习)17.bitset(位操作)
说明:bitset 就像 vector 一样,是 C++ 的一个类模板库,用来对一个数的二进制位进行管理.判断等操作,使用时需要包含头文件 #include<bitset>. 1.声明及定 ...
- 关于C/C++的一些思考(1)
C++的前世今生: C的结构化思想: Ada的模版思想: Fortran的运算符重载思想: Simula的OO思想:封装,继承,多态: C++类型描述了变量的三个特征: 该类型在内存中占用物理空间的大 ...
- HDFS的Java API 对文件的操作
在本次操作中所用到的命令 1.首先启动HDFS $HADOOP_HOME/sbin/start-dfs.sh 2.关防火墙 切换到root用户,执行service iptables stop 3.拷贝 ...
- Java中Date类型的工具类
package com.mytripod.util; import java.text.DateFormat; import java.text.SimpleDateFormat; import ja ...
- c++基础_杨辉三角形
#include <iostream> using namespace std; int main(){ int n; cin>>n; ][]; ;i<n;i++){ a ...
- Spring Quartz 和 Spring Task使用比较
Quartz 和 Spring Task执行时间对比: 1. Quartz同步模式:一个任务的两次执行的时间间隔是:“执行时间”和“trigger的设定间隔”的最大值 2. Task默认同步模式:一个 ...
- 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 ...
- [转]ionic或者angularjs中图片显示压缩问题解决 or 显示较大图片的某一块区域、裁剪显示
我们知道在html中显示图片一般都是用img控件标签,当然调整大小的也很容易. 但是会出现,特定的img大小,显示一张比较大尺寸的且长宽比例与特定img大小不相符的图片.而导致压缩问题,图片挤压的很严 ...