Waits mit SQL Server ASYNC_NETWORK_IO analysieren

cover image of blog article 'Waits mit SQL Server ASYNC_NETWORK_IO analysieren'

Wartezeiten und deren zugehörige Typen in SQL Server sind eine komplizierte Sache, die oft fundiertes Verständnis von der Materie verlangen. Die Auswirkung oder Ursache eines bestimmten Wartezeit-Typen nachzuvollziehen oder erklären zu können, ist wiederum ein anderer Sachverhalt.

In diesem Artikel gehen wir auf die ASYNC_NETWORK_IO Statistik genauer ein und erklären, wie Wartezeiten zustande kommen und welche Maßnahmen ergriffen werden können, um diesen auf den Grund zu gehen.

In verschiedenen Sachbüchern oder Fachartikeln wird die Statistik oft folgendermaßen beschrieben:

“Occurs on network writes when the task is blocked behind the network. Verify that the client is processing data from the server.”

Einfacher ausgedrückt handelt es sich bei ASYNC_NETWORK_IO um eine Wartezeit die entsteht, wenn der SQL Server Daten an einen Client gesendet hat und auf dessen Bestätigung wartet, dass dieser die Daten erfolgreich empfangen und verarbeitet hat. Gelegentlich kann sie auch im Zusammenhang mit Replikation auftreten, wenn der verarbeitende Gegenpart langsamer läuft.

Die Statistik wurde mit SQL Server 2005 eingeführt und ist bis heute Teil des Systems. Intern korrespondiert die Statistik mit NETWORK_IO map_value in der (sog.) dynamic management view sys.dm_xe_map_values. Der zugehörige Schlüssel map_key entspricht in allen Versionen bis SQL Server 2014 RTM dem Wert 99. In Versionen nach 2014 RTM muss der Schlüssel selbständig überprüft werden, da er teilweise abweicht.

Problembehandlung

In den meisten Fällen deutet die Wartezeit-Statistik ASYNC_NETWORK_IO nicht direkt auf Probleme mit dem SQL Server oder dem Netzwerk hin, sonder eher auf den “konsumierenden” Part - also den Client.

Einer einfache Methode ist die Netzwerkverbindung auf Probleme bzgl. Wartezeiten zu überprüfen und die Netzwerklatenz mit einem einfachen Ping zwischen SQL Server und Client anzuschauen. Anschließend wird das Ergebnis mit ASYNC_NETWORK_IO verglichen. Sollte die Ping-Zeit ungefähr der durchschnittlichen Wartezeit entsprechen, handelt es sich um die normale Latenz im Netz und ist kein Grund zur Sorge.

SQL Server seitig können wir nicht viel tun, um die Wartezeit zu verringern. Stattdessen sollten die externen Faktoren, wie beispielsweise der konsumierende Client näher begutachtet werden:

Oftmals kann es sein, dass der Client die erhaltenen Daten nach dem RBAR-Prinzip (Row-By-Agonizing-Row) verarbeitet. Hier wird eine Zeile nach der Anderen verarbeitet und erst im Anschluss die Antwort mit der erfolgreichen Verarbeitung an den SQL Server zurückgesendet. Stattdessen sollte der Client die erhaltenen Informationen cachen, eine Erfolgsmeldung zurücksenden und anschließend mit der Verarbeitung beginnen.

Eventuell gibt es auch allgemeine Performance Probleme mit dem Client.

Der Client Code könnte unter Umständen auf einer fehlerhaft konfigurierten VM laufen.

Eine der wenigen Möglichkeiten eine Wartezeit verursachen können, ist die Verwendung von MARS (Multiple Active Result Sets) mit größeren Abfragen order Bulk-Copy-Vorgänge. In diesen Fällen könnte es unter Umständen helfen die Paketgröße, also die Anzahl der Zeilen, zu erhöhen.

Um zu identifizieren welcher Client die Wartezeiten verursacht, können wir die Extended Events verwenden, um nach dem ASYNC_NETWORK_IO Wartezeit-Typen zu suchen. Innerhalb dieser Events geben sqlserver.client_app_name und/oder sqlserver.client_hostname Aufschluss über den Client.

Als letzte Alternative bietet sich noch die Betrachtung der NIC Einstellungen. Die benötigten Einstellungen variieren hier oft stark von Betriebssystem zu Betriebssystem und können ausschlaggebend für die Wartezeit sein.

Fehlermeldungen und Call Stacks

Bei der Wartezeitenanalyse trifft man in der Regel dann auf folgende Fehlermeldungen, aus denen abgeleitete Call Stacks hervorgehen:

  1. SOS_Task::PostWait+90 EventInternal::Wait+25c FWaitForNewPacket+e4 CNetConnection::FWaitForNewPacket+27 CNetConnection::FReadTdsPacket+6a CNetByteStream::ReadTDSPacketFromNetwork+114 CNetByteStream::EsetBeginNewStream+c1 process_commands+261 SOS_Task::Param::Execute+21e SOS_Scheduler::RunTask+a8

  2. SOS_Task::PostWait+90 EventInternal::Wait+25c WaitForReadDataDirect+fe FReadDataDirect+6d CNetConnection::FReadTdsPacket+201 CNetByteStream::ReadTDSPacketFromNetwork+114 CNetByteStream::EsetBeginNewStream+c1 process_commands+261 SOS_Task::Param::Execute+21e SOS_Scheduler::RunTask+a8

  3. SOS_Task::PostWait+90 EventInternal::Wait+25c WaitOnWriteAsyncToFinish+148 write_data+168 flush_buffer+f2 CTds74::SendRowImpl+795 0x00007FFB5D117ED7 CXStmtQuery::ErsqExecuteQuery+471 CXStmtSelect::XretExecute+2f7 CMsqlExecContext::ExecuteStmts<1,1>+400 CMsqlExecContext::FExecute+a33 CSQLSource::Execute+866

  4. SOS_Task::PostWait+90 EventInternal::Wait+25c FWaitForNewPacket+e4 CNetConnection::FWaitForNewPacket+27 CNetConnection::FReadTdsPacket+6a CNetByteStream::ReadTDSPacketFromNetwork+114 CNetByteStream::MoveToNextBuffer+7e CNetByteStream::FGetNextUnicodeFragment+34 CNetByteStream::PWCStrmConvertToWCharStream+60 CLanguageExecEnv::GetCommandInput+75 process_request+63f process_commands+51c SOS_Task::Param::Execute+21e SOS_Scheduler::RunTask+a8

Treten diese Fehlermeldungen bei Ihnen auf, sollten Sie Ihren Wartezeiten auf den Grund gehen und den Ursprung ergründen. Mit der oben beschriebenen Methode sollten Sie in der Lage sein, aussagekräftige Analyseergebnisse erzielen zu können. Diese bilden schlussendlich die Basis für eine Optimierungsmaßnahme.

Gerne helfen wir Ihnen dabei, Ihre Wartezeiten zu untersuchen und erarbeiten gemeinsam entsprechende Lösungsansätze zur Optimierung. Kontaktieren Sie uns gerne für ein unverbindliches Beratungsgespräch oder ein SQL Health Check zur Überprüfung Ihrer Umgebung.