Я знаю, що ви здебільшого стурбовані UPDATE
та здебільшого щодо продуктивності, але, як співробітник "ORM", дозвольте дати вам інший погляд на проблему розмежування значень "змінені" , "нульові" та "за замовчуванням" , які є три різні речі в SQL, але можливо лише одне в Java та в більшості ORM:
Переклад обґрунтування у INSERT
твердження
Ваші аргументи на користь забірності та кеш-пам'яті висловлювань відповідають дійсності так само, INSERT
як і для UPDATE
операторів. Але у випадку INSERT
тверджень, опущення стовпця із твердження має іншу семантику, ніж у UPDATE
. Це означає подати заявку DEFAULT
. Наступні два семантично еквівалентні:
INSERT INTO t (a, b) VALUES (1, 2);
INSERT INTO t (a, b, c) VALUES (1, 2, DEFAULT);
Це не вірно UPDATE
, коли перші два семантично еквівалентні, а треті мають зовсім інше значення:
-- 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;
Більшість API клієнтських баз даних, включаючи JDBC, і, як наслідок, JPA, не дозволяють прив'язувати DEFAULT
вираз до змінної прив'язки - в основному тому, що і сервери цього не дозволяють. Якщо ви хочете повторно використовувати один і той же оператор SQL для вищезгаданих причин збіжності та кешування можливостей оператора, ви використовуєте наступне твердження в обох випадках (якщо вважати (a, b, c)
, що всі стовпці в t
):
INSERT INTO t (a, b, c) VALUES (?, ?, ?);
А оскільки c
не встановлено, ви, ймовірно, прив'язуєте Java null
до третьої змінної прив'язки, оскільки багато ORM також не можуть розрізняти NULL
та DEFAULT
( jOOQ , наприклад, тут є винятком). Вони бачать лише Java null
і не знають, означає це NULL
(як у невідомому значенні) чи DEFAULT
(як у неініціалізованому значенні).
У багатьох випадках це відмінність не має значення, але якщо ваш стовпець c використовує будь-яку з наведених нижче функцій, твердження просто невірно :
- У ньому є
DEFAULT
пункт
- Це може бути згенеровано тригером
Повернутися до UPDATE
тверджень
Хоча вищезазначене справедливо для всіх баз даних, я можу запевнити, що тригерна проблема стосується і бази даних Oracle. Розглянемо наступний 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;
Коли ви запустите вище, ви побачите такий вихід:
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
Як бачимо, оператор, який завжди оновлює всі стовпці, завжди буде спрацьовувати тригер для всіх стовпців, тоді як заяви, оновлені лише стовпці, що змінилися, запускають лише ті тригери, які слухають такі конкретні зміни.
Іншими словами:
Поточна поведінка Hibernate, яку ви описуєте, є неповною і навіть може вважатися неправильною за наявності тригерів (і, ймовірно, інших інструментів).
Я особисто думаю, що ваш аргумент оптимізації кешу запитів завищений у випадку динамічного SQL. Звичайно, у такому кеші буде ще кілька запитів, і потрібно виконати трохи більше розбору, але це, як правило, не є проблемою для динамічних UPDATE
операторів, набагато менше, ніж для SELECT
.
Виробництво пакетів, безумовно, є проблемою, але, на мою думку, не слід нормалізувати єдине оновлення для оновлення всіх стовпців лише тому, що є невелика можливість того, що заява може бути доступним. Швидше за все, ORM може збирати підгрупи послідовних однакових висловлювань та створювати пакетні дані замість "цілої партії" (у випадку, якщо ORM навіть здатний відстежувати різницю між "зміненим" , "нульовим" та "за замовчуванням"
UPDATE
є практично еквівалентним знакуDELETE
+INSERT
(тому що ви фактично створюєте новий V -рядок рядка). Накладні витрати великі і зростають із кількістю індексів , особливо якщо багато стовпців, що їх складають, фактично оновлюються, і дерево (або будь-яке інше), що використовується для представлення індексу, потребує значних змін. Релевантна не кількість стовпців, які оновлюються, але чи оновлення стовпця індексу.