浅析SQL Server 中的SOS_SCHEDULER_YIELD类型的等待

时间:2021-06-28 19:29:27

本文出处:http://www.cnblogs.com/wy123/p/6856802.html

进程的状态转换

  在说明SOS_SCHEDULER_YIELD等待之前,先简要介绍一下进程的状态(迷迷糊糊记得操作系统原理课上讲过,三态五态转换的,比下面这个图要复杂,大部分都还给老师了)。

  如下图,分别是:运行态,阻塞态,就绪态。各个状态之间的转换关系及粗略原因如下:
  运行态-->阻塞态,原因:等待某种资源的完成,比如IO等。
  阻塞态-->就绪态,原因:锁请求的资源已完成,加入获取CPU队列中(going directly to the bottom of the Runnable Queue for the scheduler)。
  运行态-->就绪态,原因:用完了一个CPU的时间片周期(当前线程仍未完成,需要CPU资源),那么就等待进入下一个时间片周期。
              (因为一个线程不会永久性占用CPU,CPU资源而是各个线程轮询占用的一个过程)

浅析SQL Server 中的SOS_SCHEDULER_YIELD类型的等待

SOS_SCHEDULER_YIELD类型等待

SQL Server中的调度机制也类似于进程的三态模型,运行,阻塞,就绪。

关于SOS_SCHEDULER_YIELD的问题之一是SOS_SCHEDULER_YIELD这种等待类型并非一种真正的等待,
当此种等待类型发生的时候,原因是线程耗尽了它的4ms的(时间片)轮询周期,并且自动地让出(voluntary yields)CPU资源,
直接被调度器排列在可执行新线程队列的末尾,绕过等待信息列表,
此时的线程由执行态转换为就绪态,虽然此等待记录为SOS_SCHEDULER_YIELD等待,并不是因为真正的资源等待所导致的的。

而是CPU轮询周期完成之后,当前线程任务仍没有完成,需要等待轮询下一个周期来获取CPU资源执行导致的。
也就是说当然线程的执行一直在就绪和执行态之间转换,从中可以推断出当前线程是一个较为耗费CPU的操作。

浅析SQL Server 中的SOS_SCHEDULER_YIELD类型的等待

不少参考资料上都是是扫描( large scans happening ),如下
You want to investigate these waits if they’re a prevalent wait on your server,
as they could be an indicator of large scans happening (of data that’s already in memory)
where you’d really rather have small index seeks.
不过本人觉得这是全表或者索引扫描是仅仅存在的原因之一
其他有可能的原因,比如Hash Join,大结果集的Sort,Distinct等等,都是比较耗费CPU的。
另外就是,如果CPU确实比较忙,比如操作系统上的进程很多,CPU使用率很高
一个线程从就绪态到运行态需要等待的时间也会变长,因为等待占用CPU时间片的线程比较多。
总之,要明白的是,产生SOS_SCHEDULER_YIELD等待是因为当前线程需要耗费大量的CPU资源,
而CPU的调用机制是分时间片轮询供各个线程使用的,当前线程在CPU周期结束的时候,仍旧没有完成运算任务
那么就要等到下一个CPU周期去获取CPU资源,SOS_SCHEDULER_YIELD等待因此产生。

总结

  SOS_SCHEDULER_YIELD类型等待并非真正意义上的等待资源,
  而是CPU的一种调度机制导致较为耗费CPU资源的线程在执行过程中轮询获取CPU资源的一种现象。
  有可能是线程运行的SQL语句本身性能较低,比如全面扫描之类的,或者是SQL语句本身逻辑运算,产生了Hash Join,排序之类的
  如果发现有非常严重的SOS_SCHEDULER_YIELD类型等待,也应该慎重对待,比如从执行计划等方面去分析是否是正常的
  是否确实是数据高CPU使用类型的查询,否则就要从SQL语句入手分析优化了。

参考:https://www.zhihu.com/question/53125711
  :https://www.sqlskills.com/blogs/paul/identifying-queries-with-sos_scheduler_yield-waits/