SQL Server 任务调度
SQL Server 内部集成了一个专用的操作系统,叫做SQLOS,处于SQL Server和Windows的中间层。SQLOS是一个协同式的多任务调度系统,使用非抢占式争用资源,用于管理线程调度、IO争用、内存管理和资源协调。在执行查询请求时,SQL Server充分利用系统的所有资源(CPU,Memory,Disk IO),争取在最短时间内返回结果。在拥有多个处理器的系统中,如果将一个查询请求的工作负载(Wordload)分布在多个处理器上,那么每个处理器只处理一部分数据,这将成倍的减少执行查询请求的时间消耗,相应地,成倍的提高查询性能。
一,主动退让
调度系统算法采用的是非抢占式争用CPU资源和主动退让策略,主动退让(voluntarily yield)是指在调度器(Scheduler)上运行的Worker都是以非抢占模式来争用CPU资源的。Worker 会一直在一个Scheduler上运行,直到运行结束,或者主动将Scheduler 让出给其他Worker为止。SQL Server定义了很多Yield的规则,约束一个Task占用Scheduler运行的时间,保证Task在合适的时间点主动Yield,不至于占用Scheduler 太多时间,使其他Task等待太久。当Task 主动Yield时,查询请求(Request)处于SOS_SCHEDULER_YIELD等待类型。Worker 也会因为阻塞而主动退让,如果一个Worker在运行过程中被锁或是其他资源阻塞,那么该Worker就会让出Scheduler,来让其它Worker运行,当前Worker处于阻塞状态。
二,并发执行
在多处理器系统中,SQL Server可以同时执行多个任务。SQL Server优化器在发现一个Task比较复杂时,会生成多个子Task,使用多个Thread并发执行该Task,从而提高整个Task的执行效率,减少Task的执行时间。
SQL Server执行并发调度的时间包括:初始化时间,同步时间和终止并发执行所需要的时间,这些都是使用并发调度的开销,因此,只有当一个查询请求会执行“很长”的时间,它才能从并发执行中获得收益。如果查询请求执行完成的时间较短,应该使用串行方式执行。
优化器预估执行计划的开销,当开销大于服务器选项“Cost Threshold of Parallelism”时,优化器认为查询请求的执行时间是长的,使用并发方式执行任务;当开销小于“Cost Threshold of Parallelism”,优化器认为查询请求的执行时间是短的,使用串行方式执行任务。
1,影响并发调度的选项
SQL Server通过选项:Cost Threshold of Parallelism 和 Maximum Degree of Parallelism 来控制并发度,这两个选项都是服务器级别的选项。
- Maximum DOP(Degree of Parallelism)选项控制执行查询请求的最大并发度,也就是说,该选项控制优化器在同一时间可以使用的并发线程的最大数量,决定了一个Task并发执行的线程的最大数量。
- Cost Threshold of Parallelism 选项决定一个Task是否以并发方式执行,默认值是5。当SQL Server 编译查询语句时,总是先做单线程的执行计划,同时计算执行计划的开销(Cost)。如果发现这个执行计划的Cost 值大于Cost Threshold of Parallelism 选项设置的值,那么SQL Server 就会改用并行执行计划。如果提高Cost Threshold of Parallelism 选项的值,SQL Server 会提高做并行执行计划的标准,从而减少并发执行的Task数量。
2,配置并发度选项
并发阈值选项(Cost Threshold for Parallelism)的默认值是5,一般不需要修改默认值。在执行查询请求时,SQL Server 优化器估计执行计划的开销,如果开销大于并发的阈值,那么SQL Server使用多个Thread(每个CPU上在同一时间只能运行一个Thread),以多个线程并发执行查询请求;如果低于并发阈值,那么SQL Server 使用单个Thread串行执行查询请求。并发执行有一定的管理开销(Overhead),如果优化器估计执行一个查询的开销十分小,SQL Server 创建并发执行结构体的时间消耗都会比完成整个查询的时间消耗高,那就得不偿失。所以,不是所有的查询请求都适合并发执行,对于选项 cost threshold for parallelism ,决定是否使用多线程执行查询请求,不经过认真的测试,不要更改默认值。
如果SQL Server 以并发方式执行单个查询请求,那么SQL Server分配的进程数量是由并发度选项(max degree of parallelism )决定的。由于CPU资源的有限,如果为一个Task分配全部的CPU资源,那么在Task并发执行期间,其他用户的Task就会得不到及时的响应。Task的并发度和多用户的并发度是互斥的,为了平衡这种并发度,一般设置Maximum Degree of Parallelism 为CPU总数的1/4,既能够以并发执行计划快速提高单个Task的执行性能,也能兼顾用户的并发度,及时响应其他用户的Request。
这两个选项是高级选项,可以使用以下脚本修改默认的并发阈值和并发程度:
sp_configure 'show advanced options', 1; GO reconfigure; GO sp_configure 'cost threshold for parallelism', 6; GO reconfigure; GO sp_configure 'show advanced options', 1; GO RECONFIGURE WITH OVERRIDE; GO sp_configure 'max degree of parallelism', 8; GO RECONFIGURE WITH OVERRIDE; GO
三,调度产生的等待类型
由于SQLOS采用主动退让和多任务并发调用的模式,因此,当CPU资源或线程资源得不到满足时,会产生阻塞,以等待请求的资源得到满足。
1,SOS_SCHEDULER_YIELD
SOS_SCHEDULER_YIELD是在多任务调度系统中才会出现的等待类型,多任务是指服务器拥有多核,可以同时处理多个任务。SOS_SCHEDULER_YIELD等待类型就发生在一个任务放弃当前占用的资源,让其他任务使用资源能够执行下去。SQL Server以协同模式运行,在必要的时候,SQL Server会让出资源给其他线程,通常来说,这种让步是临时的,但是,当长期、大量出现这种等待的时候,有可能意味着CPU存在压力。
当Task主动Yield时,查询请求处于SOS_SCHEDULER_YIELD等待,等待被重新调用。多数情况下,出现 SOS_SCHEDULER_YIELD 等待是由于查询语句正在进行表或索引扫描,原因可能是缺失相应的索引,统计信息过期,优化器选择差的查询计划,产生参数嗅探,或者查询脚本强制不适用索引等
2,CXPACKET
CXPACKET 等待类型是SQL Server 并发执行一个查询请求时产生的。在查询请求以并行方式运行时,有些线程执行的快,有些线程执行的慢,会导致线程之间不能同时完成任务。当有 Task 先完成任务,在等待其他兄弟Task的处理完成,此时,查询请求处于CXPACKET等待。如果系统中该等待出现次数过多,时间过长,通过增加索引等不能减少该等待,考虑调整增加并发阈值(cost threshold for parallelism)和降低并发度(max degree of parallelism),以减少并发调度任务的数量。
例如,SQL Server并发执行一个查询请求,如果服务器的MDP=6,那么同时将会有7个Thread来执行这个查询请求,其中有一个Thread是Master Thread,其他的被称作Child Thread。Master Thread负责给Child Thread分配任务,最后把Child Thread返回的结果结合(combine)在一起;Child Thread负责执行特定的任务。由于Child Thread 被分配的Workload可能是不平均,每个Child Thread获取资源的开销也是不同的,因此他们执行的速度是不相同的。当一些Child Thread完成任务之后,需要等待其他未完成的Child Thread。这种在并发执行内部,一些Child Thread需要等待其他Child Thread完成的Wait Type就是CXPACKET。
参考文档:
cost threshold for parallelism Option
max degree of parallelism Option