2009-07-23 5 views
52

Ich verstehe, wie eine Transaktion nützlich sein kann, um ein Paar von Updates zu koordinieren. Was ich nicht verstehe, ist das Umbrechen einzelner Anweisungen in Transaktionen, was 90% von dem ist, was ich je gesehen habe. Tatsächlich ist es im realen Code nach meiner Erfahrung üblich, 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.Was macht eine Transaktion um eine einzelne Anweisung?

Gibt es in MS-SQL einen Vorteil, wenn einzelne Auswahlen, einzelne Aktualisierungen, einzelne Einfügungen oder einzelne Löschvorgänge in eine Transaktion eingeschlossen werden?

Ich vermute, das ist abergläubische Programmierung.

Antwort

45

Es tut nichts. Alle einzelnen SQL-Anweisungen (mit seltenen Ausnahmen wie Masseneinfügungen mit keinem Protokoll oder Tabelle abschneiden) sind automatisch "In einer Transaktion", ob Sie dies explizit sagen oder nicht (selbst wenn sie Millionen von Zeilen einfügen, aktualisieren oder löschen). .

EDIT: basierend auf @ Phillips Kommentar unten ... In den aktuellen Versionen von SQL Server, sogar Masseneinfügungen und Tabelle abschneiden schreiben einige Daten in das Transaktionslog, obwohl nicht so viel wie andere Operationen tun. Die entscheidende Unterscheidung von einer Transaktionsperspektive besteht darin, dass bei diesen anderen Typen von Operationen die Daten in Ihren Datenbanktabellen, die geändert werden, nicht im Protokoll in einem Zustand enthalten sind, in dem ein Rollback durchgeführt werden kann.

All dies bedeutet, dass die Änderungen, die die Anweisung an Daten in der Datenbank vornimmt, im Transaktionslog protokolliert werden, damit sie bei einem fehlgeschlagenen Vorgang rückgängig gemacht werden können.

Die einzige Funktion, die die Befehle "Begin Transaction", "Commit Transaction" und "RollBack Transaction" bieten, ist, dass Sie zwei oder mehr einzelne SQL-Anweisungen in dieselbe Transaktion einfügen können.

EDIT: (um Mark Kommentar zu verstärken ...) JA, könnte dies auf "abergläubische" Programmierung zurückzuführen sein, oder es könnte ein Hinweis auf ein grundlegendes Missverständnis über die Art der Datenbanktransaktionen sein. Eine gemeinnützige Interpretation ist, dass es einfach das Ergebnis einer Überdosierung von Konsistenz ist, die ein weiteres Beispiel für Emersons Euphemismus unangemessen und noch ist, dass:

Eine törichte Konsistenz der Kobold kleiner Geister ist,
von wenig verehrten Staatsmänner und Philosophen und Denker

+3

Sie sollten bestätigen, ja, das ist abergläubische Programmierung. =) –

+0

@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 verhält als andere relationale Produkte. Eines der neueren nicht-relationalen Datenbankprodukte, wie noSQL, könnte unter einem anderen Paradigma arbeiten, aber ich würde wetten, dass MySQL das gleiche ist. –

2

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

Dies ist, was Sie brauchen oder nicht brauchen.

Zum Beispiel möchten Sie möglicherweise vorläufige Ergebnisse in die äußere Welt zeigen, während immer noch eine Sperre auf ihnen.

In diesem Fall starten Sie eine andere Transaktion, die eine Sperranforderung stellt, bevor der erste somit verpflichtet, Race-Bedingung

Implizite Transaktionen vermieden werden festgelegt, oder zurück immediatley gerollt, nachdem die DML Anweisung abgeschlossen ist oder nicht.

+0

Ah, feiner Unterschied. Aber es ist nicht wirklich ein Vorteil von expliziten Transaktionen, ich würde denken, dass die zusätzliche Zeit, die explizite Transaktionssperren einzelner Kontoauszugs-Transaktionen eine klare Verlust/Verlust-Situation sind - geringere Leistung und geringere Gleichzeitigkeit, wenn auch für wahrscheinlich Millisekunden. – MatthewMartin

+1

@MatthewMartin: Ich sagte nichts von Vor- oder Nachteilen, ich habe nur den Unterschied erklärt. Bei Transaktionen geht es nicht nur um Leistung. Zum Beispiel möchten Sie möglicherweise vorläufige Ergebnisse in die äußere Welt zeigen, während Sie immer noch eine Sperre für sie halten. In diesem Fall starten Sie eine andere Transaktion, die vor dem ersten Commit eine Sperranforderung stellt, um die Race Condition zu vermeiden. In diesem Fall müssen Sie diese einzelne Anweisung noch in eine Transaktion umbrechen. – Quassnoi

+0

SQL Server unterstützt echte verschachtelte Transaktionen nicht. Einen anderen zu beginnen, ist eine schlechte Idee. http://www.sqlskills.com/BLOGS/PAUL/post/A-SQL-Server-DBA-myth-a-day-(2630)-nested-transactions-are-real.aspx – IamIC

5

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

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 in ihrer Gesamtheit funktioniert, oder nicht - und während die Anweisung ausgeführt wird, nein andere Abfragen können auf die betroffenen Daten durchgeführt werden. BEGIN TRANSACTION/COMMIT "erweitert" diese Sperrfunktion auf die Arbeit, die von mehreren Anweisungen ausgeführt wird, fügt jedoch keinen einzelnen Anweisungen hinzu.

jedoch das Datenbank-Transaktionsprotokoll ist immer geschrieben, wenn eine Datenbank modifiziert wird (Einfügen, Aktualisieren, Löschen). Dies ist keine Option, eine Tatsache, die dazu neigt, Menschen zu irritieren. Ja, es gibt Gewöhnlichkeit mit Masseneinfügungen und Wiederherstellungsmodi, aber es wird immer noch geschrieben.

Ich werde Namen-Drop Isolationsstufen auch hier. Wenn Sie damit fertig werden, wirkt sich dies auf einzelne Befehle aus, aber dies führt trotzdem nicht dazu, dass eine Abfrage mit deklarierter Transaktionsabfolge eine andere als eine "eigenständige" Abfrage ausführt. (Beachten Sie, dass sie sehr mächtig und sehr gefährlich sein können, wenn Transaktionen mit mehreren Anweisungen deklariert werden.) Beachten Sie auch, dass "nolock" nicht für Einfügungen/Aktualisierungen/Löschungen gilt - diese Aktionen erfordern immer Sperren.

+0

@Philip, Thx, bei der Untersuchung Ihres Kommentars entdeckte ich, dass sich die Dinge für "Bulk Insert" geändert haben, seit ich diese Funktion zuletzt überprüft habe (SQL 7 oder SQL2k) ... –

+0

Aber zwei eigenständige Abfragen, die in einem einzigen Befehl ohne eine explizite Transaktion aus Code ausgeführt werden, würden als zwei implizite Transaktionen in der Datenbank mit all diesen Mitteln in Bezug auf Isolationsstufen und schmutzige/geschriebene Daten ausgeführt. – Henrik

2

Eine mögliche Entschuldigung ist, dass diese einzelne Anweisung dazu führen könnte, dass eine Menge anderer SQL über Trigger läuft, und dass sie gegen etwas Schlechtes darin schützen, obwohl ich erwarten würde, dass jedes DBMS den gesunden Menschenverstand hat Verwenden Sie implizite Transaktionen auf die gleiche Weise bereits.

Die andere Sache, die ich denken kann, ist, dass einige APIs Autocommit deaktivieren können, und der Code nur für den Fall geschrieben wird, dass jemand das tut.

+1

SQL Server-Trigger werden in einer impliziten Transaktion des DML-Codes ausgeführt, der sie ausgelöst hat. Und ja, MS SQL ermöglicht es Ihnen, Autocommit zu deaktivieren. Siehe: http://msdn.microsoft.com/en-us/library/aa259220(SQL.80).aspx –

3

Für mich bedeutet das Umbrechen einer einzelnen Anweisung in einer Transaktion, dass ich sie zurückrollen kann, wenn ich beispielsweise eine WHERE-Klausel bei der Ausführung einer manuellen, einmaligen UPDATE-Anweisung 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 

-------------------------------------------------------------- 
+2

Vielleicht war meine Frage nicht klar. Ich bezog mich auf Code wie: beginnen tran; Aktualisierung foo set col1 = null; commit tran; Das wird als eine einzelne Charge ausgeführt. Dies ist ein häufiges Muster in mehreren Codebasen, die ich beibehalten habe, und es ist auch häufig zu sehen, wenn Sie den SQL-Wert ermitteln, den eine vorhandene App ausgibt. Sie beschreiben einen interaktiven Prozess, der in zwei diskreten Schritten ausgeführt wird. – MatthewMartin