Schreckliche Leistung bei der Verwendung von SqlCommand-Async-Methoden

Bin ich mit großen SQL-performance-Probleme bei der Verwendung von asynchronen Aufrufe. Ich habe eine kleine Falle um das problem zu demonstrieren.

Habe ich erstellen Sie eine Datenbank auf einem SQL Server-2016, welche sich in unserem LAN (also nicht eine localDB).

In dieser Datenbank habe ich eine Tabelle WorkingCopy mit 2 Spalten:

Id (nvarchar(255, PK))
Value (nvarchar(max))

DDL

CREATE TABLE [dbo].[Workingcopy]
(
    [Id] [nvarchar](255) NOT NULL, 
    [Value] [nvarchar](max) NULL, 

    CONSTRAINT [PK_Workingcopy] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
                    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

In dieser Tabelle, die ich eingefügt haben, die einen einzelnen Datensatz (id='PerfUnitTest', Value ist ein 1,5 mb string (zip einer größeren JSON-Datensatz)).

Nun, wenn ich die Abfrage ausführen, die in SSMS :

SELECT [Value] 
FROM [Workingcopy] 
WHERE id = 'perfunittest'

Bekomme ich sofort das Ergebnis, und ich sehe in SQL Servre Profiler, dass der Zeitpunkt der Ausführung war rund 20 Millisekunden. Alle normal.

Beim ausführen der Abfrage aus .NET (4.6) code mit einem einfachen SqlConnection :

//at this point, the connection is already open
var command = new SqlCommand($"SELECT Value FROM WorkingCopy WHERE Id = @Id", _connection);
command.Parameters.Add("@Id", SqlDbType.NVarChar, 255).Value = key;

string value = command.ExecuteScalar() as string;

Die Ausführungszeit für diese ist auch etwa 20-30 Millisekunden.

Aber wenn es zu verändern async-code :

string value = await command.ExecuteScalarAsync() as string;

Die Ausführungszeit ist plötzlich 1800 ms ! Auch in SQL Server Profiler, sehe ich, dass die Ausführung der Abfrage Dauer mehr als eine Sekunde. Obwohl der ausgeführten query berichtet von der profiler ist genau die gleiche wie die nicht-Async-version.

Aber es kommt noch schlimmer. Wenn ich spielen, um mit der Paketgröße in der Verbindungszeichenfolge, bekomme ich folgende Ergebnisse :

Packet size-32768 : [TIMING]: ExecuteScalarAsync in SqlValueStore ->
verstrichene Zeit : 450 ms

Paketgröße von 4096 : [TIMING]: ExecuteScalarAsync in SqlValueStore ->
verstrichene Zeit : 3667 ms

Packet size 512 : [TIMING]: ExecuteScalarAsync in SqlValueStore ->
verstrichene Zeit : 30776 ms

30,000 ms!! Das ist über 1000 mal langsamer als die nicht-async-version. Und SQL Server Profiler-Berichte, die die Ausführung der Abfrage dauerte über 10 Sekunden. Das auch nicht erklären, wo die anderen 20 Sekunden sind Weg!

Dann hab ich wieder eingeschaltet, um die sync-version und auch rumprobiert mit der Paket-Größe, und obwohl es hat Auswirkungen ein wenig der Zeitpunkt der Ausführung, der war nicht so dramatisch, wie mit dem async-version.

Nebenbei, wenn es nur eine kleine Zeichenkette (< 100bytes) in den Wert, der asynchrone Ausführung der Abfragen ist genauso schnell wie die sync-version (Ergebnis in 1 oder 2 ms).

Ich bin wirklich verblüfft über diese, vor allem, da ich die eingebaute SqlConnection, nicht einmal ein ORM. Auch bei der Suche rund um, ich fand nichts, was erklären könnte dieses Verhalten. Irgendwelche Ideen?

1,5 MB ????? Und Sie Fragen, warum das abrufen, wird langsamer mit Abnehmender Paketgrößen? Vor allem, wenn Sie die Verwendung der falsch Abfrage für BLOBs?
Das war nur Herumspielen im Auftrag von OP. Die eigentliche Frage ist, warum async ist so viel langsamer im Vergleich zur Synchronisierung mit dieselbe Paket-Größe.
Check Ändern von Großem Wert (max) - Daten in ADO.NET für die richtige Möglichkeit zum abrufen von CLOBs und BLOBs. Statt, zu versuchen, Sie zu Lesen, als einen großen Wert, nutzen GetSqlChars oder GetSqlBinary abrufen, die Ihnen im streaming-Mode. Berücksichtigen Sie auch speichern Sie Sie als FILESTREAM-Daten - es gibt keinen Grund zu sparen, 1.5 MB an Daten in die Daten der Tabelle Seite
Das ist nicht korrekt. OP schreibt sync : 20-30 ms und async mit sonst alles gleich 1800 ms. Die Wirkung der änderung der Paketgröße ist völlig klar und zu erwarten.
es scheint, dass Sie konnten, entfernen Sie den Teil über Ihre versuche, ändern die Packungsgrößen, da es scheint irrelevant für das problem und führt zu Verwirrung bei einigen Kommentatoren.

InformationsquelleAutor hcd | 2017-02-23

Schreibe einen Kommentar