Wenn ich eine UPDATE
Anweisung habe, die tatsächlich keine Daten ändert (weil sich die Daten bereits im aktualisierten Zustand befinden). Gibt es einen Leistungsvorteil, wenn die WHERE
Klausel überprüft wird , um das Update zu verhindern?
Zum Beispiel würde sich die Ausführungsgeschwindigkeit zwischen UPDATE 1 und UPDATE 2 wie folgt unterscheiden:
CREATE TABLE MyTable (ID int PRIMARY KEY, Value int);
INSERT INTO MyTable (ID, Value)
VALUES
(1, 1),
(2, 2),
(3, 3);
-- UPDATE 1
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2
AND Value <> 2;
SELECT @@ROWCOUNT;
-- UPDATE 2
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2;
SELECT @@ROWCOUNT;
DROP TABLE MyTable;
Der Grund, den ich frage, ist, dass die Zeilenanzahl die unveränderte Zeile enthalten muss, damit ich weiß, ob ich eine Einfügung durchführen soll, wenn die ID nicht vorhanden ist. Als solches habe ich das UPDATE 2 Formular verwendet. Wenn die Verwendung des Formulars UPDATE 1 einen Leistungsvorteil mit sich bringt, ist es dann möglich, die Anzahl der Zeilen zu ermitteln, die ich irgendwie benötige?
sql-server
query-performance
update
Martin Brown
quelle
quelle
Antworten:
Dies kann durchaus sein, da es aufgrund von UPDATE 1 einen geringfügigen Leistungsunterschied gibt :
Wie groß der Unterschied ist, müsste von Ihnen auf Ihrem System anhand Ihres Schemas, Ihrer Daten und der Systemlast gemessen werden. Es gibt verschiedene Faktoren, die bestimmen, wie stark sich ein nicht aktualisiertes UPDATE auswirkt:
UPDATE TableName SET Field1 = Field1
, wird ein Update-Trigger ausgelöst , der angibt, dass das Feld aktualisiert wurde (wenn Sie dies mit den Funktionen UPDATE () oder COLUMNS_UPDATED überprüfen ) und dass das Feld in beidenINSERTED
und denDELETED
Tabellen den gleichen Wert hat.Der folgende zusammenfassende Abschnitt ist auch in Paul Whites Artikel " Die Auswirkungen nicht aktualisierender Updates" zu finden (wie von @spaghettidba in einem Kommentar zu seiner Antwort vermerkt):
Bitte beachten Sie (insbesondere, wenn Sie nicht dem Link folgen, um den vollständigen Artikel von Paul anzuzeigen) die folgenden beiden Punkte:
Aktualisierungen, die nicht aktualisiert werden, weisen noch einige Protokollaktivitäten auf, die darauf hinweisen, dass eine Transaktion beginnt und endet. Es findet nur keine Datenänderung statt (was immer noch eine gute Einsparung ist).
Wie oben erwähnt, müssen Sie auf Ihrem System testen. Verwenden Sie dieselben Suchanfragen, die Paul verwendet, und prüfen Sie, ob Sie dieselben Ergebnisse erhalten. Ich sehe auf meinem System etwas andere Ergebnisse als in dem Artikel gezeigt. Es müssen noch keine schmutzigen Seiten geschrieben werden, sondern etwas mehr Protokollaktivität.
Vereinfacht gesagt, wenn Sie sich nur mit einer einzelnen Zeile befassen, können Sie Folgendes tun:
Bei mehreren Zeilen können Sie mithilfe der
OUTPUT
Klausel die Informationen abrufen, die für diese Entscheidung erforderlich sind . Indem Sie genau erfassen, welche Zeilen aktualisiert wurden, können Sie die Elemente eingrenzen, um den Unterschied zwischen dem Nicht-Aktualisieren von nicht vorhandenen Zeilen und dem Nicht-Aktualisieren von vorhandenen Zeilen, die jedoch nicht aktualisiert werden müssen, zu ermitteln.Ich zeige die grundlegende Implementierung in der folgenden Antwort:
Wie vermeide ich die Verwendung der Zusammenführungsabfrage, wenn mehrere Daten mit dem xml-Parameter aktualisiert werden?
Die in dieser Antwort gezeigte Methode filtert keine vorhandenen Zeilen heraus, die noch nicht aktualisiert werden müssen. Dieser Teil könnte hinzugefügt werden, aber Sie müssen zunächst genau angeben, woher Sie Ihr Dataset beziehen, in dem Sie zusammenführen
MyTable
. Kommen sie von einem temporären Tisch? Ein tabellenwertiger Parameter (TVP)?UPDATE 1:
Ich konnte endlich einige Tests durchführen und hier ist, was ich in Bezug auf Transaktionsprotokoll und Sperren gefunden habe. Zuerst das Schema für die Tabelle:
Als nächstes aktualisiert der Test das Feld auf den Wert, den es bereits hat:
Ergebnisse:
Zum Schluss der Test, der das Update herausfiltert, weil sich der Wert nicht ändert:
Ergebnisse:
Wie Sie sehen, wird beim Herausfiltern der Zeile nichts in das Transaktionsprotokoll geschrieben, im Gegensatz zu den beiden Einträgen, die den Anfang und das Ende der Transaktion markieren. Und obwohl es stimmt, dass diese beiden Einträge fast nichts sind, sind sie immer noch etwas.
Außerdem ist das Sperren der Ressourcen PAGE und KEY weniger restriktiv, wenn die nicht geänderten Zeilen herausgefiltert werden. Wenn keine anderen Prozesse mit dieser Tabelle interagieren, ist dies wahrscheinlich kein Problem (aber wie wahrscheinlich ist das wirklich?). Denken Sie daran, dass diese Tests, die in einem der verlinkten Blogs (und sogar in meinen Tests) gezeigt werden, implizit davon ausgehen, dass keine Konflikte auf dem Tisch liegen, da sie niemals Teil der Tests sind. Zu sagen, dass nicht aktualisierte Updates so leicht sind, dass sich das Filtern nicht lohnt, muss mit einem Salzkorn genommen werden, da die Tests mehr oder weniger im luftleeren Raum durchgeführt wurden. In der Produktion ist diese Tabelle jedoch höchstwahrscheinlich nicht isoliert. Natürlich könnte es durchaus sein, dass das bisschen Protokollieren und restriktivere Sperren nicht zu einer geringeren Effizienz führen. Die zuverlässigste Informationsquelle zur Beantwortung dieser Frage? SQL Server. Speziell:Ihren SQL Server. Es wird Ihnen zeigen, welche Methode für Ihr System besser ist :-).
UPDATE 2:
Wenn die Vorgänge, bei denen der neue Wert mit dem aktuellen Wert übereinstimmt (dh keine Aktualisierung), die Vorgänge übersteigen, bei denen der neue Wert abweicht und die Aktualisierung erforderlich ist, kann sich das folgende Muster als noch besser erweisen, insbesondere wenn Auf dem Tisch liegt viel Streit. Die Idee ist, zuerst einen einfachen
SELECT
Schritt zu machen, um den aktuellen Wert zu erhalten. Wenn Sie keinen Wert erhalten, haben Sie Ihre Antwort bezüglich derINSERT
. Wenn Sie einen Wert haben, können Sie einen einfachen Wert nur dannIF
ausgeben, wenn er benötigt wird.UPDATE
Ergebnisse:
Es werden also nur 2 statt 3 Sperren erworben, und beide Sperren sind Absichtsfreigaben, nicht Absichtsexklusiv oder Absichtsaktualisierung ( Sperrenkompatibilität ). Berücksichtigt man, dass jede erworbene Sperre auch freigegeben wird, handelt es sich bei jeder Sperre tatsächlich um 2 Vorgänge. Bei dieser neuen Methode handelt es sich also um insgesamt 4 Vorgänge anstelle der 6 Vorgänge der ursprünglich vorgeschlagenen Methode. Berücksichtigt man, dass dieser Vorgang einmal alle 15 ms ausgeführt wird (ungefähr, wie vom OP angegeben), dh ungefähr 66 Mal pro Sekunde. Der ursprüngliche Vorschlag umfasst also 396 Sperr- / Entsperrvorgänge pro Sekunde, während diese neue Methode nur 264 Sperr- / Entsperrvorgänge pro Sekunde für noch leichtere Sperren umfasst. Dies ist keine Garantie für großartige Leistung, aber auf jeden Fall einen Test wert :-).
quelle
Zoomen Sie ein wenig heraus und denken Sie über das größere Bild nach. In der Realität wird Ihre Update-Anweisung folgendermaßen aussehen:
Oder wird es eher so aussehen:
Denn in der realen Welt haben Tabellen viele Spalten. Das bedeutet, dass Sie eine Menge komplexer dynamischer Anwendungslogik generieren müssen, um dynamische Zeichenfolgen zu erstellen, ODER Sie müssen jedes Mal den Vorher-Nachher-Inhalt jedes Felds angeben.
Wenn Sie diese Aktualisierungsanweisungen dynamisch für jede Tabelle erstellen und nur die zu aktualisierenden Felder übergeben, können Sie schnell auf ein Problem mit der Cache-Verschmutzung stoßen , das dem Problem mit den NHibernate-Parametergrößen seit einigen Jahren ähnelt . Schlimmer noch, wenn Sie die Aktualisierungsanweisungen in SQL Server erstellen (wie in gespeicherten Prozeduren), brennen Sie wertvolle CPU-Zyklen, da SQL Server die Verkettung von Zeichenfolgen in großem Maßstab nicht besonders effizient ausführt.
Aufgrund dieser Komplexität ist es normalerweise nicht sinnvoll, diese Art von zeilenweisem, feldweisem Vergleich durchzuführen, während Sie die Aktualisierungen durchführen. Denken Sie stattdessen an satzbasierte Operationen.
quelle
Das Überspringen von Zeilen, die nur dann nicht aktualisiert werden müssen, wenn die Anzahl der Zeilen groß ist (weniger Protokollierung, weniger schmutzige Seiten zum Schreiben auf die Festplatte), kann zu einer Leistungsverbesserung führen.
Bei einzeiligen Aktualisierungen wie in Ihrem Fall ist der Leistungsunterschied völlig vernachlässigbar. Wenn das Aktualisieren der Zeilen in jedem Fall für Sie einfacher ist, tun Sie es.
Weitere Informationen zum Thema finden Sie unter Keine Aktualisierung von Updates von Paul White
quelle
Sie können das Update kombinieren und in eine Anweisung einfügen. Unter SQL Server können Sie eine MERGE- Anweisung verwenden, um das Update durchzuführen und einzufügen, wenn es nicht gefunden wird. Für MySQL können Sie INSERT ON DUPLICATE KEY UPDATE verwenden .
quelle
Anstatt die Werte aller Felder zu überprüfen, können Sie anhand der gewünschten Spalten keinen Hash-Wert ermitteln und diesen dann mit dem in der Tabelle gespeicherten Hash-Wert in Bezug auf die Zeile vergleichen.
quelle