Ich weiß, dass Sie sich UPDATE
hauptsä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 INSERT
Aussagen
Ihre Argumente für die Stapelbarkeit und die Zwischenspeicherbarkeit von Anweisungen gelten in gleicher Weise für INSERT
Anweisungen wie für UPDATE
Anweisungen. Bei INSERT
Anweisungen 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 DEFAULT
Ausdrucks 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 c
nicht festgelegt ist, würden Sie Java wahrscheinlich null
an die dritte Bindungsvariable binden, da viele ORMs auch nicht zwischen NULL
und unterscheiden können DEFAULT
( JOOQ ist hier beispielsweise eine Ausnahme). Sie sehen nur Java null
und 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
DEFAULT
Klausel
- Es kann durch einen Trigger generiert werden
Zurück zu den UPDATE
Aussagen
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 UPDATE
Anweisungen, 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 ).
UPDATE
praktisch 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.