Ich weiß, dass Sie sich UPDATEhauptsächlich um die Leistung und vor allem um die Leistung kümmern. Lassen Sie mich jedoch als Mitbetreuer von ORM eine weitere Perspektive auf das Problem der Unterscheidung zwischen den Werten "changed" , "null" und "default" geben drei verschiedene Dinge in SQL, aber möglicherweise nur eines in Java und in den meisten ORMs:
Übersetzen Sie Ihre Begründung in INSERTAussagen
Ihre Argumente für die Stapelbarkeit und die Zwischenspeicherbarkeit von Anweisungen gelten in gleicher Weise für INSERTAnweisungen wie für UPDATEAnweisungen. Bei INSERTAnweisungen hat das Weglassen einer Spalte in der Anweisung eine andere Semantik als in UPDATE. Es bedeutet, sich zu bewerben DEFAULT. Die folgenden zwei sind semantisch äquivalent:
INSERT INTO t (a, b) VALUES (1, 2);
INSERT INTO t (a, b, c) VALUES (1, 2, DEFAULT);
Dies trifft nicht zu UPDATE, wenn die ersten beiden semantisch äquivalent sind und die dritte eine ganz andere Bedeutung hat:
-- These are the same
UPDATE t SET a = 1, b = 2;
UPDATE t SET a = 1, b = 2, c = c;
-- This is different!
UPDATE t SET a = 1, b = 2, c = DEFAULT;
Die meisten Datenbank-Client-APIs, einschließlich JDBC und folglich JPA, lassen das Binden eines DEFAULTAusdrucks an eine Bindungsvariable nicht zu - hauptsächlich, weil die Server dies ebenfalls nicht zulassen. Wenn Sie dieselbe SQL-Anweisung aus den oben genannten Gründen der Stapelbarkeit und der Zwischenspeicherbarkeit von Anweisungen wiederverwenden möchten, verwenden Sie in beiden Fällen die folgende Anweisung (vorausgesetzt, (a, b, c)alle Spalten sind in t):
INSERT INTO t (a, b, c) VALUES (?, ?, ?);
Und da dies cnicht festgelegt ist, würden Sie Java wahrscheinlich nullan die dritte Bindungsvariable binden, da viele ORMs auch nicht zwischen NULLund unterscheiden können DEFAULT( JOOQ ist hier beispielsweise eine Ausnahme). Sie sehen nur Java nullund wissen nicht, ob dies NULL(wie im unbekannten Wert) oder DEFAULT(wie im nicht initialisierten Wert) bedeutet.
In vielen Fällen spielt diese Unterscheidung keine Rolle. Wenn Ihre Spalte c jedoch eine der folgenden Funktionen verwendet, ist die Aussage einfach falsch :
- Es hat eine
DEFAULTKlausel
- Es kann durch einen Trigger generiert werden
Zurück zu den UPDATEAussagen
Obwohl das oben Gesagte für alle Datenbanken zutrifft, kann ich Ihnen versichern, dass das Auslöserproblem auch für die Oracle-Datenbank zutrifft. Betrachten Sie das folgende SQL:
CREATE TABLE x (a INT PRIMARY KEY, b INT, c INT, d INT);
INSERT INTO x VALUES (1, 1, 1, 1);
CREATE OR REPLACE TRIGGER t
BEFORE UPDATE OF c, d
ON x
BEGIN
IF updating('c') THEN
dbms_output.put_line('Updating c');
END IF;
IF updating('d') THEN
dbms_output.put_line('Updating d');
END IF;
END;
/
SET SERVEROUTPUT ON
UPDATE x SET b = 1 WHERE a = 1;
UPDATE x SET c = 1 WHERE a = 1;
UPDATE x SET d = 1 WHERE a = 1;
UPDATE x SET b = 1, c = 1, d = 1 WHERE a = 1;
Wenn Sie den obigen Befehl ausführen, wird die folgende Ausgabe angezeigt:
table X created.
1 rows inserted.
TRIGGER T compiled
1 rows updated.
1 rows updated.
Updating c
1 rows updated.
Updating d
1 rows updated.
Updating c
Updating d
Wie Sie sehen, löst die Anweisung, die immer alle Spalten aktualisiert, immer den Auslöser für alle Spalten aus, während die Anweisungen, die nur geänderte Spalten aktualisieren, nur die Auslöser auslösen, die auf solche spezifischen Änderungen warten.
Mit anderen Worten:
Das aktuelle Verhalten von Hibernate, das Sie beschreiben, ist unvollständig und kann bei Vorhandensein von Triggern (und wahrscheinlich anderen Tools) sogar als falsch angesehen werden.
Ich persönlich denke, dass Ihr Argument zur Optimierung des Abfrage-Cache im Fall von dynamischem SQL überbewertet ist. Sicher, in einem solchen Cache gibt es ein paar mehr Abfragen und ein bisschen mehr Parsing-Arbeit, aber dies ist normalerweise kein Problem für dynamische UPDATEAnweisungen, viel weniger als für SELECT.
Batching ist sicherlich ein Problem, aber meiner Meinung nach sollte ein einzelnes Update nicht normalisiert werden, um alle Spalten zu aktualisieren, nur weil die Möglichkeit gering ist, dass die Anweisung Batch-fähig ist. Möglicherweise kann der ORM Untergruppen aufeinanderfolgender identischer Anweisungen sammeln und diese anstelle der "gesamten Gruppe" stapeln (falls der ORM sogar in der Lage ist, den Unterschied zwischen "geändert" , "null" und "Standard" zu verfolgen ).
UPDATEpraktisch gleichbedeutend mit einemDELETE+INSERT(weil Sie tatsächlich eine neue erstellen V ersion der Reihe). Der Overhead ist hoch und wächst mit der Anzahl der Indizes , insbesondere wenn viele der Spalten, aus denen sie bestehen, tatsächlich aktualisiert werden und der Baum (oder was auch immer), der zur Darstellung des Index verwendet wird, eine erhebliche Änderung erfordert. Es ist nicht die Anzahl der Spalten, die aktualisiert werden, sondern ob Sie einen Spaltenteil eines Indexes aktualisieren.