我正在查看生产服务器上的dm_exec_sessions和请求DMV。有些查询的状态为“已暂停”,持续时间为 12 分钟,等待类型为ASYNC_NETWORK_IO
。
我知道这是因为客户端应用程序获取数据的速度不够快(或者结果太大以至于客户端程序需要时间来使用它)。
这样的查询(由于正在进行的而被暂停ASYNC_NETWORK_IO
)是否会导致该表阻塞?
查询是 a SELECT
,我看不到此查询阻止任何其他查询。因此,我要问的问题是它是否有可能阻止任何东西。
例如:是否ASYNC_NETWORK_IO
意味着执行正在进行或执行已经完成并且客户端应用程序正在提取数据?在后一种情况下,我看不出为什么这个查询可能会阻止其他查询,因为它已经产生了结果。
查询持有的锁如下:
- 页面锁定请求方式
S
- 对象锁请求方式
IS
它可能会也可能不会。
ASYNC_NETWORK_IO
本身不能阻塞任何其他人(好吧,如果你的系统用完了工作线程,它可以,但这是一个边缘情况)。继续阅读。您说运行查询的会话是“暂停”而不是“睡眠”。根据定义,暂停的查询尚未完成。如果它已完成,它的状态将是“完成”(非常简短)或“睡眠”。
嗯,会话持有锁。这些锁会阻止任何其他需要不兼容锁的会话。换句话说,暂停的会话可能会阻止其他人,只是目前还没有。
重要的一点是会阻塞的是锁
ASYNC_NETWORK_IO
,而不是直接的状态。此时您可能会问为什么会话持有锁。
您可能有一个心智模型,其中 SQL Server 生成结果,将其存储在某处,然后结束查询并等待客户端使用结果。这不是(通常)它是如何工作的。总是在服务器上存储任意大的结果是低效和不切实际的。
相反,当结果行从执行计划中可用时,SQL Server将结果行流式传输到客户端,您可以将其视为数据“管道”。当客户端停止接收行时,管道停止,执行暂停,直到客户端再次开始请求行。
如果在会话暂停时查询持有锁,则只要暂停状态继续,这些锁就会继续持有。
旁注:
服务器和客户端之间有少量缓冲(一些网络数据包的价值),但这通常不足以保存整个结果,并且在客户端读取行清空缓冲区之前查询不会完成.
查询在挂起时并不总是持有锁。这取决于执行计划是什么样的,以及当 SQL Server 试图将下一个结果行放入缓冲区但发现没有空间时它正在做什么。
例如,一些计划可能有一个最终排序,它确实会消耗所有结果行以便对它们进行排序。在排序准备好生成输出时数据访问已经完成,因此通常不需要持有锁(取决于隔离级别等)
有关执行计划如何一次一行地流式传输行的更多信息,请参阅我的文章Iterators, Query Plans, and Why They Run Backwards。
您的查询正在运行,偶尔会进入等待类型为 ASYNC_NETWORK_IO 的“暂停”状态。
如果您的查询是 SELECT,那么是的,它可以阻止其他作者,即想要修改表的人。此答案假设您没有使用读取提交快照或快照隔离级别,并且您在悲观隔离级别下操作。