SQL Server 为什么有时候无法杀(kill)掉一个线程(spid)

有些人可能见过一种叫做non-yielding scheduler(个人解释:非让步调度器程序)的现象。在这种情况下,线程正在使用处理器,并且在使用超过线程量程(4毫秒,不可更改)后不会自动退出。有一个名为调度器监视器的后台任务,它检查SQL Server内的各种调度器上的进度,并在发现问题时发出警告。对于non-yielding Scheduler程序,你会看到错误17883,如下所示:

Process 56:0:0 (0xdee) Worker 0x041611F6 appears to be non-yielding on Scheduler 2.
Thread creation time: 13884536031127. Approx Thread CPU Used: kernel 18 ms, user 263 ms.
Process Utilization 0%. System Idle 98%. Interval: 331220558 ms.

可能发生这种情况的原因有很多,包括I/O子系统问题、对Windows API的缓慢调用或SQL Server错误。
官网解释

在SQL Server错误的情况下,这是因为线程做了一些特殊处理,它能够在不检查4ms量程是否已经过期的情况下循环(通过调用SQLOS函数YieldAndCheckForAbort,或几种变体之一)。如果线程不检查量程是否已经过期,它不会知道,因此不会让步,然后您就拥有了一个非让步调度程序。错误是缺少对 YieldAndCheckForAbort 的调用。

你可能想杀死这个线程的SPID。可以运行该命令,但它可能不会执行任何操作。这是因为没有办法在SQL Server中'强制'终止这个线程。因为线程必须检查它是否被要求终止,然后它终止自己(以及它在执行并行操作时可能创建的任何子线程)。猜猜这个检查在哪里完成?在YieldAndCheckForAbort函数中!所以如果线程缺少对 YieldAndCheckForAbort 的调用,它就不会知道,所以不会终止。

这就是为什么有时无法kill掉一些线程,最终不得不重新启动 SQL Server。

posted @ 2021-11-25 12:07  VicLW  阅读(1715)  评论(0编辑  收藏  举报