Basit bir döngü neden ASYNC_NETWORK_IO ile sonuçlanır?


19

Aşağıdaki T-SQL, SSMS v17.9 ile makinemde yaklaşık 25 saniye sürüyor:

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;

Her ASYNC_NETWORK_IOikisine göre 532 ms bekleme süresi biriktirir sys.dm_exec_session_wait_statsve sys.dm_os_wait_stats. Döngü yineleme sayısı arttıkça toplam bekleme süresi artar. wait_completedGenişletilmiş olayı kullanarak, beklemenin kabaca birkaç istisna dışında her 43 ms'de bir olduğunu görebilirsiniz:

bekleme masası

Ayrıca, ASYNC_NETWORK_IObeklemeden hemen önce oluşan çağrı yığınlarını alabilirim :

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

Son olarak, SSMS'nin döngü sırasında şaşırtıcı miktarda CPU kullandığını fark ettim (ortalama olarak yaklaşık yarım çekirdek). Bu süre zarfında SSMS'nin ne yaptığını anlayamıyorum.

Basit bir döngü neden ASYNC_NETWORK_IOSSMS aracılığıyla yürütüldüğünde bekler? Bu sorgu yürütme istemciden almak gibi görünen tek çıkış "Komutlar başarıyla tamamlandı." İleti.

Yanıtlar:


31

Dokümantasyon için SET NOCOUNTdiyor ki:

SET NOCOUNT ONDONE_IN_PROCsaklı yordamdaki her deyim için istemciye ileti gönderilmesini engeller . Çok fazla gerçek veri döndürmeyen birkaç ifade içeren saklı yordamlar veya Transact-SQL döngüleri içeren yordamlar SET NOCOUNTiçinON ağ trafiği büyük ölçüde azalır, çünkü önemli bir performans artışı sağlayabilir.

Saklı bir yordamda deyimleri çalıştırmıyorsunuz, bu nedenle SQL Server her SQL deyiminin tamamlanma durumunu belirtmek için DONEbelirteçler (kod 0xFD) gönderir . Bu iletiler ertelenir ve ağ paketi dolduğunda eşzamansız olarak gönderilir. İstemci ağ paketlerini yeterince hızlı tüketmediğinde, arabellekler dolar ve işlem SQL Server için engeller ve ASYNC_NETWORK_IObeklemeleri oluşturur.

DONEBelirteçlerin , dokümantasyon notlarından DONEINPROC(kod 0xFF) farklı olduğunu unutmayın :

  • DONEDeğişken bildirimleri dışında SQL toplu işindeki her SQL ifadesi için bir simge döndürülür.

  • Saklı yordamlar içinde SQL deyimlerinin yürütülmesi için DONEPROCve DONEINPROCbelirteçlerin yerine DONEbelirteçler kullanılır.

Şunları ASYNC_NETWORK_IOkullanarak bekleme sayısında çarpıcı bir azalma göreceksiniz :

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_executesqlAynı sonucu elde etmek için de kullanabilirsiniz .

ASYNC_NETWORK_IOBekleme başlar başlamaz yakalanan örnek yığın izlemesi :

paket gönderme

Satır içi işlevinde görüldüğü gibi örnek bir TDS paketi sqllang!srv_completioncode_ex<1>aşağıdaki 13 bayta sahipti:

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

Hangi kod çözme:

  • TokenType = 0xfd DONE_TOKEN
  • Durum = 0x0001 DONE_MORE
  • CurCmd = 0x00c1 (193)
  • DoneRowCount = 0x00000001 (1)

Sonuçta, ASYNC_NETWORK_IObekleme sayısı müşteriye ve sürücüye ve eğer varsa, tüm DONEmesajlarla ne yaptığına bağlıdır . Soruda verilen boyutun 1 / 10'u bir döngü ile test (5.000.000 döngü yinelemesi) SSMS'nin yaklaşık 4 saniye boyunca 200-300 ms beklemeyle çalıştığını buldum. sqlcmdtek haneli ms bekleme ile 2-3 saniye koştu;osqlaynı çalışma süresi etrafında yaklaşık 10 ms bekler.

Bu test için bugüne kadarki en kötü müşteri Azure Data Studio'ydu. Neredeyse 6 saat sürdü:

ADS

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.