UPDATE
Çoğunlukla performanstan ve çoğunlukla performanstan endişe duyduğunuzu biliyorum , ancak bir "ORM" destekçisi olarak size "değiştirilmiş" , "boş" ve "varsayılan" değerleri ayırt etme sorununa başka bir bakış açısı sunayım. SQL'de üç farklı şey, ancak Java'da ve çoğu ORM'de muhtemelen tek bir şey:
Gerekçenizi INSERT
ifadelere çevirme
Toplu işlenebilirlik ve ifade önbelleğe alınabilirliği konusundaki argümanlarınız, ifadeler için INSERT
olduğu gibi UPDATE
ifadeler için de geçerlidir. Ancak INSERT
ifadeler söz konusu olduğunda, ifadeden bir sütunu atlamak, içinde olduğundan farklı bir anlambilime sahiptir UPDATE
. Uygulamak demektir DEFAULT
. Aşağıdaki ikisi anlamsal olarak eşdeğerdir:
INSERT INTO t (a, b) VALUES (1, 2);
INSERT INTO t (a, b, c) VALUES (1, 2, DEFAULT);
UPDATE
İlk ikisinin anlamsal olarak eşdeğer olduğu ve üçüncüsünün tamamen farklı bir anlamı olduğu için bu doğru değildir :
-- 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 ve sonuç olarak JPA dahil olmak üzere çoğu veritabanı istemcisi API'si, bir DEFAULT
ifadeyi bağlama değişkenine bağlamaya izin vermez - çoğunlukla sunucular buna izin vermez. Yukarıda belirtilen toplu işlenebilirlik ve ifade önbelleğe alınabilirlik nedenleriyle aynı SQL ifadesini yeniden kullanmak istiyorsanız, her iki durumda da aşağıdaki ifadeyi kullanırsınız ( (a, b, c)
tüm sütunlar varsa t
):
INSERT INTO t (a, b, c) VALUES (?, ?, ?);
Ve c
ayarlanmadığından, muhtemelen Java'yı null
üçüncü bağlama değişkenine bağlarsınız, çünkü birçok ORM aynı zamandaNULL
ve ileDEFAULT
( jOOQ , örneğin bir istisna). Sadece Java'yı görürler null
ve bunun NULL
(bilinmeyen değerde DEFAULT
olduğu gibi ) veya (başlatılmamış değerdeki gibi ) anlamına gelip gelmediğini bilmezler .
Çoğu durumda, bu ayrım önemli değildir, ancak c sütununuz aşağıdaki özelliklerden herhangi birini kullanıyorsa, ifade yanlıştır :
- Bir
DEFAULT
maddesi var
- Bir tetikleyici tarafından oluşturulmuş olabilir
UPDATE
İfadelere geri dön
Yukarıdakiler tüm veritabanları için geçerli olsa da, tetikleyici sorununun Oracle veritabanı için de doğru olduğundan emin olabilirsiniz. Aşağıdaki SQL'i düşünün:
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;
Yukarıdakileri çalıştırdığınızda, aşağıdaki çıktıyı göreceksiniz:
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
Gördüğünüz gibi, her zaman tüm sütunları güncelleyen ifade her zaman tüm sütunlar için tetikleyiciyi tetiklerken, yalnızca değişen sütunları güncelleyen ifadeler yalnızca bu tür belirli değişiklikleri dinleyen tetikleyicileri tetikler.
Diğer bir deyişle:
Hazırladığınız Hibernate'in mevcut davranışı eksiktir ve hatta tetikleyicilerin (ve muhtemelen diğer araçların) varlığında yanlış kabul edilebilir.
Şahsen dinamik SQL durumunda sorgu önbellek optimizasyonu argümanının abartıldığını düşünüyorum. Elbette, böyle bir önbellekte birkaç sorgu daha yapılacak ve biraz daha ayrıştırma çalışması yapılacak, ancak bu genellikle dinamik UPDATE
ifadeler için olduğundan daha az bir sorun değildir SELECT
.
Toplu işlem kesinlikle bir sorundur, ancak benim görüşüme göre, tüm sütunları güncellemek için tek bir güncelleme normalleştirilmemelidir, çünkü ifadenin küçük bir olasılığı olabilir. Muhtemelen ORM, ardışık özdeş ifadelerin alt gruplarını toplayabilir ve "tüm toplu iş" yerine bunları toplu olarak işleyebilir (ORM'nin "değiştirilmiş" , "boş" ve "varsayılan" arasındaki farkı bile izleyebilmesi durumunda)
UPDATE
a pratik olarak birDELETE
+ değerine eşdeğerdirINSERT
(çünkü satırın yeni bir V sürümünü oluşturursunuz). Tepegöz yüksektir ve özellikle bunları içeren sütunların çoğu gerçekten güncellenirse ve dizini temsil etmek için kullanılan ağacın (veya herhangi bir şeyin) önemli bir değişikliğe ihtiyacı varsa dizin sayısı ile birlikte büyür . Alakalı olanın güncellenen sütun sayısı değil, bir dizinin sütun kısmını güncelleyip güncellemediğiniz.