Verwenden Sie SqlTransaction & IsolationLevel für längere Lesevorgänge?

8

Ich führe mehrere lang andauernde SQL-Abfragen als Teil eines Berichtsmoduls aus. Diese Abfragen werden zur Laufzeit dynamisch erstellt. Abhängig von der Eingabe des Benutzers können sie Einzel- oder Mehrfachanweisungen sein, einen oder mehrere Parameter haben und an einer oder mehreren Datenbanktabellen arbeiten - mit anderen Worten, ihre Form kann nicht leicht vorhergesehen werden.

Momentan führe ich diese Anweisungen nur auf einem normalen SqlConnection aus, d. h.

%Vor%

Da diese Abfragen (wirklich Abfragen von Batches) eine Weile dauern können, um sie auszuführen, mache ich mir Sorgen über Sperren für Tabellen, die Lese- / Schreibvorgänge für andere Benutzer halten. Es ist kein Problem, wenn sich die Daten für diese Berichte während der Ausführung des Stapels ändern. Die Berichtsabfragen sollten niemals Vorrang vor anderen Operationen in diesen Tabellen haben, noch sollten sie sie sperren.

Bei den meisten Operationen mit langer Laufzeit und mehreren Anweisungen, bei denen Daten geändert werden, würde ich Transaktionen verwenden. Der Unterschied besteht darin, dass diese Berichtsabfragen keine Daten ändern. Würde ich diese Berichtsabfragen korrekt in ein SqlTransaction einschließen, um ihre Isolationsstufe zu kontrollieren?

d. h .:

%Vor%

Würde dies mein gewünschtes Ergebnis erreichen? Ist es richtig, eine Transaktion zu begehen, obwohl keine Daten geändert wurden? Gibt es einen anderen Ansatz?

    
Bradley Smith 24.09.2012, 07:06
quelle

2 Antworten

5

Ein anderer Ansatz könnte sein, gegen die Verbindung auszustellen:

%Vor%

das die gleiche Absicht erreicht, ohne eine Transaktion zu stören. Oder Sie könnten den WITH(NOLOCK) Hinweis für die Tabellen in Ihrer Abfrage verwenden, was den Vorteil hat, die Verbindung überhaupt nicht zu ändern.

Beachten Sie (ungewöhnlich): jedoch wird geändert (Transaktion, Transaktionsbereich, explizite SET usw.), die Isolationsstufe ist nicht wird zwischen den Verwendungen derselben zugrunde liegenden Verbindung zurückgesetzt, wenn sie aus dem Pool abgerufen wird. Dies bedeutet, dass wenn Ihr Code die Isolationsstufe (direkt oder indirekt) ändert, keiner Ihres Codes die Isolationsstufe einer neuen Verbindung kennt:

%Vor%

Was die WITH(NOLOCK) ziemlich verlockend macht.

    
Marc Gravell 24.09.2012, 07:13
quelle
1

Ich stimme Marc zu, aber alternativ könnten Sie den NOLOCK-Abfragehinweis für die betroffenen Tabellen verwenden. Dies gibt Ihnen die Möglichkeit, es auf Tabellenebene auf Tabellenebene zu steuern.

Das Problem beim Ausführen von Abfragen ohne gemeinsame Sperren besteht darin, dass Sie sich "nicht-deterministischen" Ergebnissen öffnen und keine Geschäftsentscheidungen für diese Daten getroffen werden sollten.

Ein besserer Ansatz könnte darin bestehen, entweder die Isolationsstufen SNAPSHOT oder READ_COMMITED_SNAPSHOT zu untersuchen. Diese bieten Ihnen Schutz vor Transaktionsanomalien, ohne dass Sie Schlösser nehmen müssen. Der Kompromiss besteht darin, dass sie IO gegenüber TempDB erhöhen. Jede dieser Ebenen kann entweder auf die Sitzung angewendet werden, wie von Marc vorgeschlagen, oder auf die Tabelle, wie ich es vorgeschlagen habe.

Hoffe, das hilft

    
Pete Carter 24.09.2012 07:20
quelle