关于SQL Server的几个基本概念 ——Connection、Session、Request、Task、Worker和Scheduler

SQL Server 是如何执行查询脚本的呢?首先,应用程序连接到SQL Server引擎, 向SQL Server发送请求。一旦应用程序连接到数据库引擎,SQL Server 创建会话(Session),用于表示客户端和服务器端之间数据交换的状态。其次,SQL Server引擎分配Task来接受查询请求,然后,SQL Server把Workder 绑定到Task,开始分配CPU资源和内存资源来处理Task。最后,通过解析、编译和优化,进入查询引擎,真正开始执行查询请求。下图从高层次上概括了SQL Server执行TSQL脚本的流程:

对于图中的相关组件,先来了解一下其基本的概念和功能,下面的术语都是在SQL Server OS中实现的。

一,Connections

连接,这是在底层协议上实现的实际的物理连接,在客户端向数据库引擎发送请求之前,必须建立应用程序和数据库引擎之间的物理链接,是应用程序和数据库引擎之间联系的物理通道,有三种连接的类型:TCP socket,命名管道(named pipe)和共享内存(shared memory)。相关的DMV:sys.dm_exec_connections。

二,Sessions

会话,当客户端应用程序连到SQL Server时,两端就会建立起一个“会话”用于交换信息。严格来说,会话不是底层的物理连接,是SQL Server对连接的逻辑表示,用于存储在数据库引擎和应用程序之间连接时所需要的设置,比如,登陆信息,事务的隔离级别,会话的SET选项等。但是,在实际应用中,通常可以把会话视为连接。

当发现一个session有多个值时,意味着出现了并行查询。一个并行查询使用相同的会话来连接客户端,但是在SQL Server端使用多个Worker(Thread)用于服务这个请求。相关DMV:sys.dm_exec_sessions,当你看到有多行数据有相同的Session ID时,这是因为SQL Server 使用多个线程来处理一个查询请求。

通常情况下,一个Connection对应一个Session,有时,可能存在多个Session对应一个Connection的情况,这是MARS(Multiple Active Result Sets)现象。

三,Request

请求,在SQL Server 的语境下,是查询或批处理的逻辑表示。SQL Server是一个 Client-Server平台,客户端与服务器(后端数据库)交互的唯一方式是通过发送包含命令的请求到数据库,而客户端与服务器端交互的协议简称为TDS(Tabular Data Stream)。应用程序使用SqlClient、OleDB、ODBC、JDBC等驱动来实现这种协议。当应用程序需要对数据库执行任何操作时,它都通过TDS协议向数据库引擎发送一个请求(request)。

简单来说,每次对数据库的操作都会以“请求”的形式发送给数据库服务器,发送请求有多种类型,主要是:Batch Request、RPC Request、Bulk Load Request。

  • Batch Request:批请求,此请求类型仅包含要执行的批处理的T-SQL文本。
  • RPC Request:远程过程调用请求(Remote Procedure Call Request),用于执行存储过程。
  • Bulk Load Request:大容量加载请求,用于执行大容量插入(Bulk Insert)操作

相关的DMV是:sys.dm_exec_requests。

四,Tasks

任务,表示SQL Server 需要处理的一个请求。一个或多个Task会被分配用于完成一个请求。在一个完整的TDS请求达到数据库引擎时,SQL Server将会创建一个任务(Task)来处理请求。当Request到达SQL Server之后,后续操作都发生在SQL Server内部。用户可以从  sys.dm_exec_requests 查看数据库引擎接收到的所有请求。一旦一个Task接收一个请求,Task的状态由PENDING 转变为可用。

当任务被创建用于处理请求时,该Task将代表请求从开始到完成的整过程。例如,如果请求是SQL Batch类型的请求,则任务将代表整个批次,而不是单个语句,SQL Batch中的单个语句不会创建新任务。批处理中的某些个别语句可以并行执行(通常称为DOP,并行度),在这种情况下,任务将产生新的子任务以并行执行。如果请求返回结果,则当客户端完全使用结果时(例如,当您处置SqlDataReader时),批处理就完成了。您可以通过查询sys.dm_os_tasks 来查看服务器中的任务列表。

当一个新请求到达服务器并且创建一个对应的任务时,首先会处于PENDING(挂起状态),任务的状态可以有:

  • PENDING:正在等待工作线程(Worker Thread)。
  • RUNNABLE:可运行,但正在等待接收一个时间片(quantum)。
  • RUNNING:当前正在Scheduler中运行。
  • SUSPENDED:拥有worker,但是正在等待某些事件(向RUNNABLE转变)
  • DONE:已经完成。
  • SPINLOOP:陷入自旋锁。

当新的请求到达服务器并创建任务以处理该请求时,处于PENDING状态。在此阶段,服务器尚不知道请求实际上是什么。该任务必须首先开始执行,为此,引擎必须为其分配一个工作程序(Worker)。

五,Workers

工作进程(Workder Thread),简称为Workder,或Thread,逻辑上对应于操作系统的线程,线程是操作系统可以执行的最小处理单元,并允许将应用程序逻辑上分为多个并发执行路径。SQL Server服务器在启动时会创建一定数量的Worker(工作程序),并且可以按需创建更多工作程序,直到配置的最大工作程序线程(max worker threads)。只有Worker才能执行代码,Worker等待PENDING任务变为可用(当Task被分配用于处理请求),然后每个Workder被分配到一个Task,并执行该Task。Workder会一直执行(running),直到任务完全完成。

当没有更多可用的Worker(工作进程)时,正在等待处理(PENDING)的任务将不得不等待,直到正在执行的(running)任务完成,或者执行该任务的Workder变得可用,能够执行下一个PENDING的任务为止。

对于一个SQL批处理请求,承担该任务的工作进程将执行整个SQL批处理(每个语句)。对于SQL批处理中的语句(=> request => task => worker)是否可以并行执行,答案是否定的,因为它们是在单个线程(=> worker)上执行的,所以每个语句必须按照顺序来执行。

对于使用并行选项(DOP> 1)的语句,SQL Server会创建子任务,每个子任务都会经历完全相同的周期:创建子任务(PENDING),工作程序必须拾取子任务并执行(与SQL批处理工作者不同的工作程序),通过查询sys.dm_os_workers可以查看SQL Server中工作程序的列表和状态。

六,Scheduler

调度程序(Scheduler)是指SOS scheduler,用于管理Worker对CPU时间的需求,协调各个Worker对CPU资源的利用。每一个Scheduler都映射到一个单独的CPU,Workder在一个调度程序中保持活跃/运行(Running)的时间称作一个时间片(Quantum),最长时长为4毫秒。在其时间片到期之后,一个Worker主动退出,把时间片让给其他需要访问CPU资源的Workder,并修改自身的状态为RUNNABLE,这种调度方式称为非抢占式调度。

SOS Scheduler是非抢占式的,数据库对各种请求分配的时间都是相同的,而操作系统的调度模式抢占式的,当出现紧急情况时,按照优先级,高优先级进程抢占把低优先级低的资源。

 

参考文档:

Thread and Task Architecture Guide

Understanding how SQL Server executes a query

Understanding how SQL Server executes a query

T-SQL执行内幕(1)——简介

posted @ 2020-05-24 12:42  悦光阴  阅读(3451)  评论(0编辑  收藏  举报