เหตุใดการวนซ้ำอย่างง่ายใน ASYNC_NETWORK_IO จึงรออยู่


19

T-SQL ต่อไปนี้ใช้เวลาประมาณ 25 วินาทีในเครื่องของฉันด้วย SSMS v17.9:

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;

มันสะสม 532 มิลลิวินาทีของASYNC_NETWORK_IOรอตามทั้งสองและsys.dm_exec_session_wait_stats 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 ใช้ซีพียูในปริมาณที่น่าประหลาดใจในระหว่างการวนรอบ ฉันไม่สามารถทราบได้ว่า SSMS กำลังทำอะไรในช่วงเวลานั้น

เหตุใดจึงทำให้การวนรอบแบบง่ายASYNC_NETWORK_IOรอเมื่อดำเนินการผ่าน SSMS ผลลัพธ์เดียวที่ฉันได้รับจากลูกค้าจากการดำเนินการค้นหานี้คือ "คำสั่งเสร็จสมบูรณ์แล้ว" ข่าวสาร

คำตอบ:


31

เอกสารสำหรับการSET NOCOUNTพูดว่า:

SET NOCOUNT ONป้องกันการส่งDONE_IN_PROCข้อความไปยังลูกค้าสำหรับแต่ละคำสั่งในขั้นตอนการจัดเก็บ สำหรับกระบวนงานที่เก็บไว้ซึ่งประกอบด้วยหลายคำสั่งที่ไม่ส่งคืนข้อมูลจริงมากหรือสำหรับขั้นตอนที่มีการวนรอบ Transact SQL การตั้งค่าSET NOCOUNTเพื่อให้ONสามารถเพิ่มประสิทธิภาพที่สำคัญเนื่องจากปริมาณการใช้เครือข่ายจะลดลงอย่างมาก

คุณไม่ได้รันคำสั่งในขั้นตอนการจัดเก็บดังนั้น SQL Server ส่งDONEโทเค็น (รหัส0xFD) เพื่อระบุสถานะความสมบูรณ์ของแต่ละคำสั่ง SQL ข้อความเหล่านี้ถูกเลื่อนออกไปและส่งแบบอะซิงโครนัสเมื่อแพ็กเก็ตเครือข่ายเต็ม เมื่อไคลเอ็นต์ไม่ใช้แพ็คเก็ตเครือข่ายเร็วพอบัฟเฟอร์ในที่สุดก็จะเต็มและการดำเนินการจะกลายเป็นบล็อกสำหรับ SQL Server สร้างการASYNC_NETWORK_IOรอ

หมายเหตุDONEโทเค็นแตกต่างจากDONEINPROC(รหัส0xFF) เป็นบันทึกเอกสาร:

  • DONEโทเค็นจะถูกส่งกลับในแต่ละคำสั่ง SQL ในชุด SQL ยกเว้นการประกาศตัวแปร

  • สำหรับการประมวลผลคำสั่ง SQL ภายในโพรซีเดอร์ที่เก็บไว้DONEPROCและDONEINPROCโทเค็นจะถูกใช้แทนDONEโทเค็น

คุณจะเห็นการลดลงอย่างมากในการASYNC_NETWORK_IOรอโดยใช้:

CREATE PROCEDURE #P AS
SET NOCOUNT ON;

DECLARE
    @outer_loop integer = 0,
    @big_string_for_u varchar(8000);


WHILE @outer_loop < 5000000
BEGIN
    SET @big_string_for_u = 'ZZZZZZZZZZ';
    SET @outer_loop = @outer_loop + 1;
END;
GO
EXECUTE dbo.#P;

คุณสามารถใช้sys.sp_executesqlเพื่อให้ได้ผลลัพธ์เดียวกัน

ตัวอย่างการติดตามสแต็กที่ASYNC_NETWORK_IOดักจับเมื่อเริ่มต้นการรอ:

ส่งแพ็คเก็ต

ตัวอย่างแพ็คเก็ต TDS ดังที่เห็นในฟังก์ชั่นแบบอินไลน์sqllang!srv_completioncode_ex<1>มี 13 ไบต์ต่อไปนี้:

fd 01 00 c1 00 01 00 00 00 00 00 00 00          

ซึ่งถอดรหัสเป็น:

  • TokenType = 0xfd DONE_TOKEN
  • สถานะ = 0x0001 DONE_MORE
  • CurCmd = 0x00c1 (193)
  • DoneRowCount = 0x00000001 (1)

ในที่สุดจำนวนการASYNC_NETWORK_IOรอขึ้นอยู่กับไคลเอนต์และไดรเวอร์และสิ่งที่มันทำถ้ามีอะไรกับDONEข้อความทั้งหมด การทดสอบด้วยลูป 1 / 10th ของขนาดที่กำหนดในคำถาม (วนซ้ำ 5,000,000 ลูป) ฉันพบ SSMS ทำงานเป็นเวลาประมาณ 4 วินาทีโดยรอ 200-300 มิลลิวินาที sqlcmdวิ่งเป็นเวลา 2-3 วินาทีโดยรอด้วยหลักหน่วยเดียว ms; osqlประมาณเวลาทำงานเดียวกันโดยรอประมาณ 10 ms

ลูกค้าที่แย่ที่สุดสำหรับการทดสอบนี้คือ Azure Data Studio มันใช้เวลาเกือบ 6 ชั่วโมง:

ADS

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.