设为首页 收藏本站
查看: 673|回复: 0

[经验分享] 理解SQL Server是如何执行查询的 (1/3)

[复制链接]

尚未签到

发表于 2017-7-13 07:28:52 | 显示全部楼层 |阅读模式
  查询执行的总图:
DSC0000.png

  根据总图的流程,详细说明每个部分:
  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事件。

  • RPC请求(Remote Procedure Call Request)
  它包含过程标识符(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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-393350-1-1.html 上篇帖子: SQL Server-聚焦深入理解动态SQL查询(三十二) 下篇帖子: PHP5.6.15连接Sql Server 2008配置方案
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表