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 INSERTifadelere çevirme
Toplu işlenebilirlik ve ifade önbelleğe alınabilirliği konusundaki argümanlarınız, ifadeler için INSERTolduğu gibi UPDATEifadeler için de geçerlidir. Ancak INSERTifadeler 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 DEFAULTifadeyi 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 cayarlanmadığı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 nullve bunun NULL(bilinmeyen değerde DEFAULTolduğ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
DEFAULTmaddesi 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 UPDATEifadeler 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)
UPDATEa 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.