나는 당신이 주로 UPDATE
성능 에 대해 걱정하고 있다는 것을 알고 있지만 동료 "ORM"관리자로서 "changed" , "null" , "default" 값 을 구별하는 문제에 대한 또 다른 관점을 제시하겠습니다. 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;
JDBC를 포함한 대부분의 데이터베이스 클라이언트 API 및 결과적으로 JPA는 바인딩을 허용하지 않습니다. DEFAULT
표현식이 바인드 변수 대부분 서버가이를 허용하지 않기 때문입니다. 위에서 언급 한 배치 가능성 및 명령문 캐시 가능성 이유로 동일한 SQL 문을 재사용하려면 두 경우 모두 다음 명령문을 사용해야합니다 ( (a, b, c)
모두 열이 모두 있다고 가정 t
).
INSERT INTO t (a, b, c) VALUES (?, ?, ?);
그리고 이후 c
설정되지 않은, 당신은 아마 바인드 자바 거라고 null
많은으로 ORMs도 구별 할 수 없기 때문에, 세 번째 바인드 변수 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이 "changed" , "null" 및 "default" 의 차이를 추적 할 수있는 경우).
UPDATE
A와 실질적으로 동일하다DELETE
+INSERT
(당신이 실제로 새로운 만들 수 있기 때문에 V의 행의 ersion을). 오버 헤드는 높고 인덱스 수에 따라 증가 합니다 . 특히이를 구성하는 많은 열이 실제로 업데이트 되고 인덱스를 나타내는 데 사용 된 트리 (또는 기타)가 크게 변경되어야하는 경우에 특히 그렇습니다. 관련 항목이 업데이트되는 열 수는 아니지만 인덱스의 열 부분을 업데이트하는지 여부입니다.