以下 T-SQL 在我的机器上使用 SSMS v17.9 大约需要 25 秒:
DECLARE @outer_loop INT = 0,
@big_string_for_u VARCHAR(8000);
SET NOCOUNT ON;
WHILE @outer_loop < 50000000
BEGIN
SET @big_string_for_u = 'ZZZZZZZZZZ';
SET @outer_loop = @outer_loop + 1;
END;
ASYNC_NETWORK_IO
根据sys.dm_exec_session_wait_stats
和,它累积了 532 毫秒的等待时间sys.dm_os_wait_stats
。总等待时间随着循环迭代次数的增加而增加。使用wait_completed
扩展事件,我可以看到等待大约每 43 毫秒发生一次,但有一些例外:
此外,我可以获取在ASYNC_NETWORK_IO
等待之前发生的调用堆栈:
sqldk.dll!SOS_DispatcherBase::GetTrack+0x7f6c
sqldk.dll!SOS_Scheduler::PromotePendingTask+0x204
sqldk.dll!SOS_Task::PostWait+0x5f
sqldk.dll!SOS_Scheduler::Suspend+0xb15
sqllang.dll!CSECCNGProvider::GetBCryptHandleFromAlgID+0xf6af
sqllang.dll!CSECCNGProvider::GetBCryptHandleFromAlgID+0xf44c
sqllang.dll!SNIPacketRelease+0xd63
sqllang.dll!SNIPacketRelease+0x2097
sqllang.dll!SNIPacketRelease+0x1f99
sqllang.dll!SNIPacketRelease+0x18fe
sqllang.dll!CAutoExecuteAsContext::Restore+0x52d
sqllang.dll!CSQLSource::Execute+0x151b
sqllang.dll!CSQLSource::Execute+0xe13
sqllang.dll!CSQLSource::Execute+0x474
sqllang.dll!SNIPacketRelease+0x165d
sqllang.dll!CValOdsRow::CValOdsRow+0xa92
sqllang.dll!CValOdsRow::CValOdsRow+0x883
sqldk.dll!ClockHand::Statistic::RecordClockHandStats+0x15d
sqldk.dll!ClockHand::Statistic::RecordClockHandStats+0x638
sqldk.dll!ClockHand::Statistic::RecordClockHandStats+0x2ad
sqldk.dll!SystemThread::MakeMiniSOSThread+0xdf8
sqldk.dll!SystemThread::MakeMiniSOSThread+0xf00
sqldk.dll!SystemThread::MakeMiniSOSThread+0x667
sqldk.dll!SystemThread::MakeMiniSOSThread+0xbb9
最后,我注意到 SSMS 在循环期间使用了惊人数量的 CPU(平均大约半个核心)。我无法弄清楚 SSMS 在那段时间里在做什么。
为什么一个简单的循环ASYNC_NETWORK_IO
在通过 SSMS 执行时会导致等待?我似乎从该查询执行中从客户端获得的唯一输出是“命令已成功完成”。信息。
的文档
SET NOCOUNT
说:您没有在存储过程中运行语句,因此 SQL Server 发送
DONE
令牌(代码0xFD
)来指示每个 SQL 语句的完成状态。这些消息被延迟,并在网络数据包已满时异步发送。当客户端没有足够快地消耗网络数据包时,最终缓冲区会填满,并且操作会阻塞 SQL Server,从而产生ASYNC_NETWORK_IO
等待。请注意,
DONE
令牌与文档说明的DONEINPROC
(code ) 不同:0xFF
您将看到使用以下命令显着减少
ASYNC_NETWORK_IO
等待:您也可以使用
sys.sp_executesql
来达到相同的结果。ASYNC_NETWORK_IO
在等待开始时捕获的示例堆栈跟踪:在内联函数中看到的示例 TDS 数据包
sqllang!srv_completioncode_ex<1>
具有以下 13 个字节:解码为:
DONE_TOKEN
DONE_MORE
最终,
ASYNC_NETWORK_IO
等待的次数取决于客户端和驱动程序,以及它对所有DONE
消息的作用(如果有的话)。使用问题中给出的大小的 1/10 循环进行测试(5,000,000 次循环迭代)我发现 SSMS 运行了大约 4 秒,等待时间为 200-300 毫秒。sqlcmd
以个位数毫秒等待运行 2-3 秒;osql
大约相同的运行时间,大约 10 毫秒的等待。迄今为止,该测试最差的客户端是 Azure Data Studio。它运行了将近 6 个小时: