Ich wollte die folgende UPDATE
-Anweisung in einer SQL Server-Datenbanktabelle ausführen:
Aus Versehen habe ich stattdessen die folgende Anweisung ausgeführt:
%Vor% Beachten Sie, dass in dieser zweiten Anweisung (die falsche) die Klausel FROM
die Tabelle TABLE_A_COPY
anstelle von TABLE_A
angibt. Beide Tabellen haben genau dasselbe Schema (d. H. Dieselben Spalten) und dieselben Daten (vor der Ausführung von UPDATE
).
Sowohl TABLE_A
als auch TABLE_A_COPY
haben ungefähr 100 Millionen Datensätze und das Update betrifft ungefähr 500.000 Datensätze. Die zweite Anweisung (die falsche) läuft mehrere Stunden lang und schlägt fehl, während die erste Anweisung (die richtige) 40 Sekunden lang ausgeführt wird und erfolgreich ist.
Offensichtlich sind beide Anweisungen syntaktisch korrekt, aber ich bin mir nicht sicher, was genau ich SQL Server mit der ersten Anweisung zu tun hatte.
Meine Fragen sind:
Was hat SQL Server in der zweiten Anweisung versucht? Bei meinem Fehler habe ich die Verknüpfung zwischen den Datensätzen von TABLE_A
bis TABLE_A_COPY
nicht angegeben, also habe ich versucht einen CROSS JOIN zwischen den beiden zu machen, und dann jeden Datensatz in TABLE_A
a milliardenfach zu aktualisieren?
Wenn es keine allzu große Frage ist, was wäre ein gültiges Szenario für eine solche UPDATE
-Anweisung, in der die aktualisierte Tabelle in den FROM/JOIN
-Klauseln nicht erwähnt wird. Warum sollte jemand das tun? Warum würde SQL Server das sogar zulassen?
Ich habe versucht, eine Antwort auf meine Fragen zu finden, aber Google scheint zu glauben, dass ich nach UPDATE FROM
syntax frage.
1) Es gibt keine Verbindung zwischen TABLE_A
und TABLE_A_COPY
, so dass Sie CROSS JOIN
erhalten und die gleiche Zeile massiv aktualisieren. Das Ergebnis kann nichtdeterministisch sein, wenn die parallele Ausführung aktiviert ist:
Überprüfen Sie den obigen Code wie TABLE_A
Datensatz mit KEY_1 = 6
geändert.
2)
SQL Server UPDATE FROM/DELETE FROM
-Syntax ist viel breiter als der ANSI-Standard. Das Problem, auf das Sie stoßen, kann auf mehrere Aktualisierungen derselben Zeile reduziert werden. Mit UPDATE
erhalten Sie keinen Fehler oder Warnung:
Von Let's deprecate UPDATE FROM!
und Deprecate UPDATE FROM and DELETE FROM
:
Korrektheit? Bah, wen interessiert das?
Nun, die meisten tun es. Deshalb testen wir.
Wenn ich die Join-Kriterien in einer SELECT-Abfrage durcheinander bringe, so dass zu viele Zeilen aus dem zweiten Tisch-Match, ich werde es sehen, sobald ich teste, weil ich bekomme mehr Zeilen zurück als erwartet. Wenn ich die Unterabfragekriterien durcheinander bringe in einer ANSI-Standard-UPDATE-Abfrage in ähnlicher Weise sehe ich es sogar früher, weil SQL Server bei der Unterabfrage einen Fehler zurückgibt gibt mehr als einen einzelnen Wert zurück. Aber mit dem proprietären UPDATE VON Syntax, ich kann den Beitritt vermasseln und nie bemerken - SQL Server wird wiederhole die gleiche Zeile immer wieder, wenn sie mehr entspricht als eine Zeile in der verbundenen Tabelle, mit nur dem Ergebnis des letzten von diese Updates kleben. Und es gibt keine Möglichkeit zu wissen, welche Zeile das ist wird sein, da das im Abfrageausführungsplan abhängt, der passiert Ausgewählt werden. Ein Worst-Case-Szenario wäre eines, bei dem die Ausführung erfolgt Plan führt zufällig zu dem erwarteten Ergebnis bei allen Tests auf dem Single-Prozessor-Entwicklungsserver - und dann danach Bereitstellung auf dem Vier-Wege-Dual-Core-Produktionsserver, unsere wertvolle Daten treffen plötzlich den Fan ...
Wenn Sie zum Beispiel MERGE
verwenden, erhalten Sie eine Fehlermeldung:
Die MERGE-Anweisung hat versucht, dieselbe Zeile mehr zu aktualisieren oder zu löschen als einmal. Dies passiert, wenn eine Zielzeile mehr als einer Quelle entspricht Reihe. Eine MERGE-Anweisung kann dieselbe Zeile des Ziels nicht aktualisieren / löschen Tabelle mehrmals. Verfeinern Sie die ON-Klausel, um eine Zielzeile sicherzustellen passt höchstens zu einer Quellzeile oder gruppiert die GROUP BY-Klausel die Quellzeilen.
Sie müssen also vorsichtiger sein und Ihren Code überprüfen. Ich möchte auch Fehler bekommen, aber wie Sie in connect Link sehen, wird dies nicht passieren.
Eine Möglichkeit, dies zu vermeiden, ist die Verwendung von UPDATE alias
, so dass Sie sicher sind, dass Sie Tabellen verwenden, die an FROM JOIN
teilnehmen und keine anderen Tabellen beteiligt sind.:
SQL wird eine Menge Dinge erlauben, die wahrscheinlich keinen Sinn machen Hinweis tableB ist auf beiden Seiten des ein
%Vor%SQL prüft nur die Syntax - es liegt an Ihnen, also schreiben Sie eine Aussage, die Sinn macht
Es könnte sein, dass Sie wirklich eine Aktualisierung des Produkttyps möchten
So würde ich diese Aussage schreiben Ich richte die Tabellennamen aus, so dass es einfacher ist,
zu sehen %Vor%Tags und Links sql-server tsql sql-update