Was macht eine Transaktion um eine einzelne Anweisung?

71

Ich verstehe, wie eine Transaktion nützlich sein kann, um ein Paar von Updates zu koordinieren. Was ich nicht verstehe, ist das Umschließen einzelner Anweisungen in Transaktionen, was 90% dessen entspricht, was ich jemals gesehen habe. Tatsächlich ist es im realen Code meiner Erfahrung nach üblicher, eine Reihe von logisch zusammenhängenden Transaktionen zu finden, die jeweils in ihre eigene Transaktion eingeschlossen sind, aber das Ganze ist nicht in eine Transaktion eingeschlossen.

Gibt es in MS-SQL einen Vorteil darin, einzelne Auswahlen, einzelne Aktualisierungen, einzelne Einfügungen oder einzelne Löschvorgänge in eine Transaktion einzuschließen?

Ich vermute, das ist abergläubische Programmierung.

MatthewMartin
quelle

Antworten:

68

Es macht nichts. Alle einzelnen SQL-Anweisungen (mit seltenen Ausnahmen wie Masseneinfügungen ohne Protokoll oder Tabelle abschneiden) werden automatisch "In einer Transaktion" angezeigt, unabhängig davon, ob Sie dies ausdrücklich sagen oder nicht. (Selbst wenn sie Millionen von Zeilen einfügen, aktualisieren oder löschen.) .

BEARBEITEN: basierend auf dem Kommentar von @ Phillip unten ... In aktuellen Versionen von SQL Server schreiben Even Bulk Inserts und Truncate Table einige Daten in das Transaktionsprotokoll, wenn auch nicht so viele wie andere Vorgänge. Der entscheidende Unterschied aus Transaktionssicht besteht darin, dass bei diesen anderen Arten von Vorgängen die Daten in Ihren Datenbanktabellen, die geändert werden, nicht im Protokoll in einem Zustand sind, in dem sie zurückgesetzt werden können.

Dies bedeutet lediglich, dass die Änderungen, die die Anweisung an Daten in der Datenbank vornimmt, im Transaktionsprotokoll protokolliert werden, sodass sie rückgängig gemacht werden können, wenn der Vorgang fehlschlägt.

Die einzige Funktion, die die Befehle "Transaktion starten", "Transaktion festschreiben" und "RollBack-Transaktion" bereitstellen, besteht darin, dass Sie zwei oder mehr einzelne SQL-Anweisungen in dieselbe Transaktion einfügen können.

BEARBEITEN: (um den Markenkommentar zu verstärken ...) JA, dies könnte auf "abergläubische" Programmierung zurückgeführt werden, oder es könnte ein Hinweis auf ein grundlegendes Missverständnis der Art von Datenbanktransaktionen sein. Eine gemeinnützigere Interpretation ist, dass es einfach das Ergebnis einer unangemessenen Überanwendung von Konsistenz ist und ein weiteres Beispiel für Emersons Euphemismus, dass:

Eine dumme Konsequenz ist der Hobgoblin kleiner Geister, der
von kleinen Staatsmännern, Philosophen und Göttern verehrt wird

Charles Bretana
quelle
4
Sie sollten bestätigen, ja, das ist abergläubische Programmierung. =)
Mark Canlas
@ Charles, was ist mit MySQL?
Pacerier
1
@Pacerier, ich spreche MySQL nicht fließend, aber ich wäre verblüfft, wenn sich ihr Produkt in dieser Hinsicht anders verhalten würde als andere relationale Produkte. Eines der neueren nicht relationalen Datenbankprodukte wie noSQL funktioniert möglicherweise unter einem anderen Paradigma, aber ich wette, MySQL ist dasselbe.
Charles Bretana
Übrigens können Sie in SQL Server tatsächlich ein Rollback durchführen TRUNCATE TABLE. in einer Transaktion Der Grund dafür, dass es immer noch effizienter ist als DELETEbei der Protokollierung, ist, dass nur die Seitenfreigaben und nicht die Zeilen protokolliert werden.
Brandon
10

Wie Charles Bretana sagte, "es tut nichts" - nichts zusätzlich zu dem, was bereits getan wurde.

Haben Sie schon einmal von den "ACID" -Anforderungen einer relationalen Datenbank gehört? Dieses "A" steht für Atomic, was bedeutet, dass entweder die Anweisung vollständig funktioniert oder nicht - und während die Anweisung ausgeführt wird, können keine weiteren Abfragen für die von dieser Abfrage betroffenen Daten durchgeführt werden. BEGIN TRANSACTION / COMMIT "erweitert" diese Sperrfunktion auf die Arbeit mehrerer Anweisungen, fügt jedoch einzelnen Anweisungen nichts hinzu.

Das Datenbanktransaktionsprotokoll wird jedoch immer geschrieben, wenn eine Datenbank geändert wird (Einfügen, Aktualisieren, Löschen). Dies ist keine Option, eine Tatsache, die dazu neigt, Menschen zu irritieren. Ja, es gibt Seltsamkeiten bei Masseneinfügungen und Wiederherstellungsmodi, aber es wird immer noch darauf geschrieben.

Ich werde auch hier Isolationsstufen benennen. Wenn Sie sich damit beschäftigen, wirkt sich dies auf einzelne Befehle aus. Wenn Sie dies tun, wird eine deklarierte, mit Transaktionen umschlossene Abfrage jedoch nicht anders ausgeführt als eine "eigenständige" Abfrage. (Beachten Sie, dass sie bei deklarierten Transaktionen mit mehreren Anweisungen sehr leistungsfähig und sehr gefährlich sein können.) Beachten Sie auch, dass "nolock" nicht für Einfügungen / Aktualisierungen / Löschungen gilt - diese Aktionen erforderten immer Sperren.

Philip Kelley
quelle
@Philip, Thx, als ich Ihren Kommentar recherchierte, stellte ich fest, dass sich die Dinge für 'Bulk Insert' geändert haben, seit ich diese Funktionalität das letzte Mal überprüft habe (SQL 7 oder SQL2k) ...
Charles Bretana
1
Zwei eigenständige Abfragen, die in einem einzigen Befehl ohne explizite Transaktion aus Code ausgeführt werden, werden jedoch als zwei implizite Transaktionen in der Datenbank ausgeführt, was alles in Bezug auf Isolationsstufen und verschmutzte / geschriebene Daten bedeutet.
Henrik
4

Wenn ich eine einzelne Anweisung in eine Transaktion einbinde, kann ich sie zurücksetzen, wenn ich beispielsweise beim Ausführen einer manuellen, einmaligen UPDATE-Anweisung eine WHERE-Klausel vergesse. Es hat mich ein paar Mal gerettet.

z.B

--------------------------------------------------------------
CREATE TABLE T1(CPK INT IDENTITY(1,1) NOT NULL, Col1 int, Col2 char(3));
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');

SELECT * FROM T1


--------------------------------------------------------------
/* MISTAKE SCENARIO     (run each row individually) */
--------------------------------------------------------------
BEGIN TRAN YOUR_TRANS_NAME_1;   /* open a trans named YOUR_TRANS_NAME_1 */
    UPDATE T1 SET COL2 = NULL;  /* run some update statement */
    SELECT * FROM T1;       /* OOPS ... forgot the where clause */
ROLLBACK TRAN YOUR_TRANS_NAME_1;    /* since it did bad things, roll it back */
    SELECT * FROM T1;       /* tans rolled back, data restored. */



--------------------------------------------------------------
/* NO MISTAKES SCENARIO (run each row individually) */
--------------------------------------------------------------

BEGIN TRAN YOUR_TRANS_NAME_2;
    UPDATE T1 SET COL2 = 'CBA' WHERE CPK = 4;   /* run some update statement */
    SELECT * FROM T1;               /* did it correctly this time */

COMMIT TRAN YOUR_TRANS_NAME_2           /* commit (close) the trans */

--------------------------------------------------------------

DROP TABLE T1

--------------------------------------------------------------
GWR
quelle
5
Vielleicht war meine Frage nicht klar. Ich bezog mich auf Code wie: begin tran; Update foo set col1 = null; tran begehen; Welches als einzelne Charge ausgeführt wird. Dies ist ein sehr häufiges Muster in mehreren Codebasen, die ich beibehalten habe, und es ist auch üblich zu sehen, wann Sie die SQL verfolgen, die eine vorhandene App ausgibt. Sie beschreiben einen interaktiven Prozess, der in zwei diskreten Schritten ausgeführt wird.
Matthewmartin
Dies ist wahr für Aussagen manuell in einem Abfrage Bearbeitungswerkzeug ausgeführt wird , da durch eine Transaktion explizit starten, das Werkzeug erfordert , dass Sie explizit commit (oder Rollback), anstatt es automatisch tun.
Charles Bretana
2

Eine mögliche Entschuldigung ist, dass diese einzelne Anweisung dazu führen kann, dass eine Reihe anderer SQL-Anweisungen über Trigger ausgeführt werden, und dass sie vor einem Fehler schützen, obwohl ich davon ausgehen würde, dass jedes DBMS den gesunden Menschenverstand hat, implizite Transaktionen zu verwenden genauso schon.

Die andere Sache, die ich mir vorstellen kann, ist, dass Sie mit einigen APIs die automatische Festschreibung deaktivieren können und der Code nur für den Fall geschrieben wurde, dass jemand dies tut.


quelle
1
SQL Server-Trigger werden in einer impliziten Transaktion des DML-Codes ausgeführt, der sie ausgelöst hat. Und ja, mit MS SQL können Sie die automatische Festschreibung deaktivieren. Siehe: msdn.microsoft.com/en-us/library/aa259220(SQL.80).aspx
Shannon Severance
2

Wenn Sie eine explizite Transaktion starten und a ausgeben DML, bleiben die von der Anweisung gesperrten Ressourcen gesperrt, und die Ergebnisse der Anweisung sind von außerhalb der Transaktion erst sichtbar, wenn Sie sie manuell festschreiben oder zurücksetzen.

Dies ist, was Sie möglicherweise benötigen oder nicht.

Zum Beispiel möchten Sie der Außenwelt möglicherweise vorläufige Ergebnisse anzeigen, während Sie diese weiterhin im Auge behalten.

In diesem Fall starten Sie eine andere Transaktion, bei der eine Sperranforderung vor der ersten Festschreibung gestellt wird, wodurch die Racebedingung vermieden wird

Implizite Transaktionen werden sofort nach DMLAbschluss oder Fehlschlagen der Anweisung festgeschrieben oder zurückgesetzt .

Quassnoi
quelle
Ah, subtiler Unterschied. Aber es ist nicht wirklich ein Vorteil von expliziten Transaktionen. Ich würde denken, dass die zusätzliche Zeit, die explizite Transaktionen zum Sperren einzelner Anweisungen benötigen, eine klare Verlust- / Verlustsituation darstellt - geringere Leistung und geringere Parallelität, wenn auch wahrscheinlich für Millisekunden.
Matthew
1
@MatthewMartin: Ich sagte nichts über Vor- oder Nachteile, ich erklärte nur den Unterschied. Bei Transaktionen geht es nicht nur um Leistung. Zum Beispiel möchten Sie vielleicht der Außenwelt vorläufige Ergebnisse zeigen, während Sie sie weiterhin im Auge behalten. In diesem Fall starten Sie eine weitere Transaktion, bei der eine Sperranforderung gestellt wird, bevor die erste festgeschrieben wird, wodurch die Racebedingung vermieden wird. In diesem Fall müssen Sie diese einzelne Anweisung noch in eine Transaktion einschließen.
Quassnoi
SQL Server unterstützt keine echten verschachtelten Transaktionen. Einen anderen zu starten ist eine schlechte Idee. sqlskills.com/BLOGS/PAUL/post/…
IamIC
1

SQL Server verfügt über eine Einstellung, mit der das automatische Festschreiben für eine Sitzung deaktiviert werden kann. Dies ist sogar die Standardeinstellung für einige Clients (siehe https://docs.microsoft.com/en-us/sql/t-sql/statements/set-implicit-transactions-transact-sql?view=sql-server-2017 ).

Abhängig von einem Framework und / oder einem Datenbankclient, den Sie verwenden, kann das Nichteinfügen jedes einzelnen Befehls in eine eigene Transaktion dazu führen, dass alle Befehle zu einer Standardtransaktion zusammengefasst werden. Das explizite Einschließen jedes einzelnen von ihnen in eine Transaktion erklärt eindeutig die Absicht und stellt tatsächlich sicher, dass dies so geschieht, wie es der Programmierer beabsichtigt hat, unabhängig von der aktuellen Einstellung für die automatische Festschreibung, insbesondere wenn es keine unternehmensweite Richtlinie für die automatische Festschreibung gibt.

Wenn die Befehle begin tran / commit tran in der Datenbank beobachtet werden (gemäß Ihrem Kommentar hier ), ist es auch möglich, dass ein Framework sie im Auftrag eines ahnungslosen Programmierers generiert. (Wie viele Entwickler überprüfen den von ihrem Framework generierten SQL-Code genau?)

Ich hoffe, dass dies immer noch relevant ist, obwohl die Frage etwas alt ist.

Martin Vajsar
quelle