理解SQL Server是如何执行查询的 (1/3)
查询执行的总图:
根据总图的流程,详细说明每个部分:
1. 请求(Request)
SQL Server是C/S架构的平台。与它交互的唯一方式就是发送包含数据库命令的请求。应用程序和数据库之前的通信协议叫做TDS(Tabular Data Stream)协议。应用程序可以使用以下几种实现了TDS协议的客户端:
- The CLR managed SqlClient,
- OleDB,
- ODBC,
- JDBC,
- PHP Driver for SQL Server
- 开源的FreeTDS
TDS的请求分为以下几类:
- 批请求(Batch Request)
这种请求只包括T-SQL文本,不包含参数,但是可以包含本地变量。在SqlClient中带有空参数列表的SqlCommand对象上执行SqlCommand.ExecuteReader(), ExecuteNonQuery(), ExecuteScalar()或者ExecuteXmlReader(),就会是批请求。通过Profile会观察到SQL:BatchStarting事件。
它包含过程标识符(Procedure Identifier,用于)和任意数理的参数。不同的过程标识符代表了不同的系统存储过程。执行带有非空参数列表的SqlCommand对象时,就是这种请求类型。通过Profile可以观察到RPC:Starting事件。
- 批量加载请求(Bulk Load Request)
批量加载是批量插入操作所使用的一种特别的请求类型。例如BCP工具、OleDB的IRowsetFastLoad接口和SqlBulkcopy类。它是唯一一种在TDS协议中不需要完成包发送就可以开始执行的请求。开始执行后,就可以使用数据流中的数据进行插入操作了。
2. 任务(Task)
当完整的请求到达数据库引擎,SQL Server会创建一个Task去处理此请求。可以通过sys.dm_exec_requests观察请求情况。一个任务代表一个完整的请求,而不会是请求的一部分语句。同样,对于请求中的部分语句,也不会创建新的任务。有些请求的中语句会并行执行,而Task会生成sub-task处理并行。当客户端取走所有请求返回的结果集中的数据后,Task就完成了。
可以通过sys.dm_os_tasks观察Task情况。
3. 工作进程(Workers)
根据新请求所创建的Task,初始状态是PENDING。这个阶段,SQL Server并不知道请求的内容。Task须要执行这个请求,引擎就会分配worker去执行。(是分配,不是创建)
Workers是SQL Server的线程池。在SQL Server启动过程中会初始化一定数量的Workers。可以通过Max_Worker_Threads参数,按需要配置最大线程数。只有Worker才执行代码。当没有空闲的worker时,task变成Pending状态。worker完成task后,变成可用状态,才会去选择Pending状态的task执行。
在SQL批请求中,worker选择task后,执行批请求中的每一个语句。很明显,批请求中语句,是串行执行的。前一个完成,才会开始下一个。批中的某些语句会并行执行,这个并行是Task创建sub-task来完成的。而每一个sub-task会经历和task一样处理过程(如等待可用的worker来选取它并执行)。
可以通过sys.dm_os_workers查看worker及其状态。
4. 语法解析和编译(Parsing & Compilation)
当task开始执行,首先它要弄明白请求的具体的内容。这个阶段SQL Server对请求中的T-SQL文本进行语法解析并生成表示请求的抽象语法树(abstract syntax tree)。整个请求会被解析和编译。如果在这个阶段产生错误,则会返回编译错误,并结果任务并释放task和worker。
编译T-SQL不会产生像本地CPU指令一样的可执行代码,也产生类似于字节码的东西。它产生查询计划(Query Plan)。查询计划描述了数据访问的路径和访问对象的方法。
5. 优化(Optimization)
优化是从很多个查询计划中选择出最优的一个。SQL Server采用基于成本的优化器。它会估算所有可能(大多数)的查询计划的成本,并选择出成本最低的一个。成本主要通过计算查询计划需要读取的数据大小(data size)。为了知道数据大小,SQL Server需要知道每个表的大小和列值的分布情况(通过统计信息数据)。成本还会考虑CPU和内存使用量。再通过一个公式将这些数据综合个成本值,然后选取出成本值最小的那个执行计划。
优化过程需要消耗时间和CPU,所以一当查询计划最终生成,则会被缓存到计划缓存中,以备重用。
6. 执行(Execution)
一旦优化器选定了执行计划,请求就可以开始执行了。执行计划会被转换成实际的执行树。树中的每个节点是一个操作符。所有操作符都实现三个抽象接口:open()、next()和close()。循环执行包括调用根节点的open(),然后逐级调用next()直到返回false,再调用close()。
叶级节点通常是一些物理数据访问操作符(访问实际的数据和索引),中间节点通常是一些实现数据过滤、排序和连接等数据操作的操作符。并行执行有一个专门的操作符:Exchange操作符。Exchange操作符发出多个线程,每个线程执行一个查询计划的子树,然后再使用multiple-producers-one-consumer 方式聚合所有子线程的输出。
数据修改操作也适用于这个执行方式。
有些操作符非常简单,如TOP(N)。当调用它的next(),它会去调用子节点的next()并记录数据。当重复执行N次后,它就返回false,并终止对子节点的调用和对相应分支子树的迭代执行。
有些操作符非常复杂,如nested loop操作符。这需要跟踪内外子节点循环迭代的位置,调用外节点的next(),值重绕(rewind)内节点并不断调用内节点的next()直到找到匹配的值。
有些操作符需要等到获取到它的所有子节点的输出数据时,才能产生自己的输出数据。这种行为方式也叫stop-and-go。如sort操作符,它第一次调用netxt(),不会返回数据,需要等到所有的数据被返回并排序,这才能返回数据。
HASH JOIN是一个非常复杂并且又是stop-and-go类型的操作符。为了构造hash表,它要调用构建侧(build side)节点的next(),直到返回false。然后再调用探测侧(probe side)的next(),直到找到在hash表中找到匹配的值,然后返回。重复探测侧的操作,直到next()返回false。
7. 返回结果(Results)
查询一旦开始执行就可以开始返回数据给客户端程序。当执行树开始产生返回数据后,最顶端的操作符会负责把数据写入网络缓存并发送给客户端。执行中产生的返回结果,不会被缓存到任何地方,一但产生就开始返回给客户端。
显然,通过网络返回数据给客户端会受到网络流量控制协议的约束。如果客户端不能及时地取走返回的数据,最终会阻塞数据发送方的发送行为,并使得查询执行被挂起。当客户端的数据接收能力正常后,发送方的发送行为和查询执行会被重置,正常产生返回结果数据。
OUTPUT参数的输出值,只能在执行计划完成后,才能被写入到数据流中。所以它也只能在所有返回结果被客户端取走后,才能被读取到。
总结:
1. 这是一篇译文,计划分为3部分。学习之用,非逐字翻译,很多是结合自己的理解译的,与原文内容相比,有一些增和删。
2. 原文地址:Understanding how SQL Server executes a query
理解SQL Server是如何执行查询的 (1/3)的更多相关文章
- 理解SQL Server是如何执行查询的 (2/3)
查询执行的内存授予(Query Execution Memory Grant) 有些操作符需要较多的内存才能完成操作.例如,SORT.HASH.HAS聚合等.执行计划通过操作符需要处理数据量的预估值( ...
- 理解SQL Server是如何执行查询的 (3/3)
页并发访问的保护:闩锁 在多线程并发情况下,需要防止读线程读到写线程正在写的资源,在编程中,通过使用互斥器(Mutexes), 信号量(Semaphore), 临界区(Critical Section ...
- 理解SQL Server是如何执行查询的---Joe-T :mvp
http://www.cnblogs.com/Joe-T/ http://rusanu.com/2013/08/01/understanding-how-sql-server-executes-a-q ...
- 理解SQL Server中的权限体系(下)----安全对象和权限
原文:http://www.cnblogs.com/CareySon/archive/2012/04/12/SQL-Security-SecurableAndPermission.html 在开始阅读 ...
- 理解SQL Server中的权限体系(上)----主体
原文:http://www.cnblogs.com/CareySon/archive/2012/04/10/mssql-security-principal.html 简介 权限两个字,一个权力,一个 ...
- (转)理解SQL SERVER中的分区表
简介 分区表是在SQL SERVER2005之后的版本引入的特性.这个特性允许把逻辑上的一个表在物理上分为很多部分.而对于SQL SERVER2005之前版本,所谓的分区表仅仅是分布式视图,也就是多个 ...
- 理解SQL Server中索引的概念
T-SQL查询进阶--理解SQL Server中索引的概念,原理以及其他 简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能 ...
- 理解SQL SERVER中的分区表(转)
简介 分区表是在SQL SERVER2005之后的版本引入的特性.这个特性允许把逻辑上的一个表在物理上分为很多部分.而对于SQL SERVER2005之前版本,所谓的分区表仅仅是分布式视图,也就是多个 ...
- 理解SQL SERVER中的分区表
转自:http://www.cnblogs.com/sienpower/archive/2011/12/31/2308741.html 简介 分区表是在SQL SERVER2005之后的版本引入的特性 ...
随机推荐
- js作用域问题一步步透彻理解
黄金守则第一条: js没有块级作用域(你可以自己闭包或其他方法实现),只有函数级作用域,函数外面的变量函数里面可以找到,函数里面的变量外面找不到. first try: 这是为什么呢?? var a ...
- Unity3D热更新全书-PageZero
由于深刻的认识到自己是个思维跳跃的人,深入浅出是个我还要努力很久的目标,为了让大家不至于在我乱七八糟的文字中迷失,特整理目录一份 无分类 <Unity3D热更新全书-何谓热更新,为何热更新,如何 ...
- Unity3D热更新全书-脚本(四) 用C#LightEvil搭建实际开发使用的脚本框架
C#LightEvil之前提供了很多和Unity结合的例子,都是采用把脚本文件放置在StreamingAssets中的方法. 这样可以利用Unity的特性,放在这个目录中的CS文件会被编译器编译,我们 ...
- Ubuntu下解决adb devices:???????????? no permissions的方法
之前一直都是在windows下进行开发的,但是这次由于一个小模块用的东西只能在linux下运行,所以就发生了这么一系列的问题环境:虚拟机Vmware下的Ubuntu12.10事件:连接android手 ...
- js模仿新浪微博限制字数输入
功能:实现新浪微博输入字数提醒功能:最多输入140个字,当输入字时,上面提示部分字数发生变化,如果字数小于25,字体颜色变红:当可输入字数为0时,强制不能输入,如果用中文输入法 一次性输入很多字,那么 ...
- 将不确定变为确定~DateTime.MinValue和MaxValue引发的异常
回到目录 问题描述: SqlDateTime 溢出.必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间 概念相关 .Net中的DateTime结 ...
- Atitit 图片 验证码生成attilax总结
Atitit 图片 验证码生成attilax总结 1.1. 图片验证码总结1 1.2. 镂空文字 打散 干扰线 文字扭曲 粘连2 1.1. 图片验证码总结 因此,CAPTCHA在图片验证码这一应用点 ...
- Atitit机器学习原理与概论book attilax总结
Atitit机器学习原理与概论book attilax总结 <机器学习(决战大数据时代!IT技术人员不得不读!)>((美)米歇尔(Mitchell)[简介_书评_在线阅读] -1 < ...
- 程序员藏经阁 Linux兵书
程序员藏经阁 Linux兵书 刘丽霞 杨宇 编 ISBN 978-7-121-21992-4 2014年1月出版 定价:79.00元 536页 16开 内容提要 <Linux兵书>由浅 ...
- fir.im Weekly - 如何打造 Github 「爆款」开源项目
最近 Android 转用 Swift 的传闻甚嚣尘上,Swift 的 Github 主页上已经有了一次 merge>>「Port to Android」,让我们对 Swift 的想象又多 ...