INSERT ON CONFLICT ifadesi atomik upsert semantiği sunar: Çakışma yoksa satırı ekler; yinelenen bir birincil anahtar algılanırsa mevcut satırı günceller veya atlar.
Verileri doğrudan SQL ile aktarırken bu ifadeyi kullanın. Data Integration ve Flink tabanlı yazma işlemleri için bkz. Kullanım durumları.
Temel kavramlar
Bu ifade üç çakışma çözümleme modunu destekler:
| Mod | SQL yan tümcesi | Yinelenen birincil anahtardaki davranış |
|---|---|---|
| InsertOrIgnore | DO NOTHING |
Gelen satırı reddeder; mevcut satır değişmez |
| InsertOrUpdate | DO UPDATE SET <columns> |
Yalnızca listelediğiniz sütunları günceller; listelenmeyen sütunlar mevcut değerlerini korur |
| InsertOrReplace | DO UPDATE SET <all columns> ile eksik sütunlar için null |
Satırın tamamını üzerine yazar; eksik sütunlar null olur |
Mod seçimi:
İlk yazan kazanır kuralını uygulamak ve mevcut verilerin üzerine yazılmamasını sağlamak istediğinizde InsertOrIgnore kullanın.
Seçici sütun güncellemelerine ihtiyaç duyduğunuzda ve eksik sütunların korunması gerektiğinde InsertOrUpdate kullanın.
Satırın tamamını değiştirmek ve eksik sütunları açıkça
nullolarak ayarlamak istediğinizde InsertOrReplace kullanın.
Kullanım durumları
INSERT ON CONFLICT ifadesi, verileri SQL deyimleri kullanarak aktardığınızda geçerlidir.
Data Integration (DataWorks)
Data Integration, yerleşik bir INSERT ON CONFLICT özelliğine sahiptir. Hologres Writer içindeki Write Conflict Policy seçeneğini yapılandırın:
Ignore — InsertOrIgnore moduna eşdeğerdir
Replace — InsertOrReplace moduna eşdeğerdir
Bu ilke hem çevrimdışı hem de gerçek zamanlı senkronizasyon için geçerlidir. Senkronizasyon sırasında verileri güncellemek için Hologres tablosunda bir birincil anahtar bulunmalıdır.
Flink
Flink yazma işlemleri için varsayılan write conflict policy değeri InsertOrIgnore şeklindedir. Bu, havuz tablosunda bir birincil anahtar gerektirir ve yinelenen bir kayıtla karşılaşıldığında ilk girişi korur. ctas sözdizimini kullandığınızda varsayılan değer InsertOrUpdate olarak değişir.
Sözdizimi
INSERT INTO <table_name> [ AS <alias> ] [ ( <column_name> [, ...] ) ]
{ VALUES ( { <expression> } [, ...] ) [, ...] | <query> }
[ ON CONFLICT [ conflict_target ] conflict_action ]
-- conflict_target
ON CONSTRAINT constraint_name
-- conflict_action
DO NOTHING
DO UPDATE SET { <column_name> = { <expression> } |
( <column_name> [, ...] ) = ( { <expression> } [, ...] ) |
} [, ...]
[ WHERE condition ]
excluded hakkında:
excluded , eklenmesi önerilen (çakışmayı tetikleyen) satıra başvurmak için kullanılan sanal bir tablo takma adıdır. Kaynak tablo için bir takma ad değildir. Gelen satırdaki belirli bir sütuna başvurmak için excluded.<column_name> veya DDL sırasındaki tüm sütunlara başvurmak için ROW(excluded.*) kullanın.
Parametreler:
| Parametre | Açıklama |
|---|---|
table_name |
Hedef tablo |
alias |
Hedef tablo için alternatif bir ad |
column_name |
Hedef tablodaki hedef sütun |
DO NOTHING |
InsertOrIgnore — yinelenen birincil anahtar varsa eklemeyi atlar |
DO UPDATE |
InsertOrUpdate veya InsertOrReplace — yinelenen birincil anahtar varsa mevcut satırı günceller |
expression |
Yazılacak değer. İlgili sütun için gelen satırın değerine başvurmak üzere excluded.<column_name> kullanın. Gelen satırın tüm sütunlarına DDL sırasına göre başvurmak için ROW(excluded.*) kullanın. |
Çalışma biçimi
INSERT ON CONFLICT , UPDATE ile aynı dahili yolu izler. Güncelleme performansı tablonun depolama formatına bağlıdır.
Sütun yönelimli tablolar
Birincil anahtarı olmayan tablolar en yüksek yazma aktarım hızını sunar. Birincil anahtarı olan tablolar için performans sıralaması şöyledir:
InsertOrIgnore > InsertOrReplace >= InsertOrUpdate (full row) > InsertOrUpdate (partial column)
Satır yönelimli tablolar
InsertOrReplace = InsertOrUpdate (full row) >= InsertOrUpdate (partial column) >= InsertOrIgnore
Satır yönelimli tablolarda en iyi performansı elde etmek için DO UPDATE SET yan tümcesindeki sütun sırasının INSERT yan tümcesiyle tutarlı olmasını sağlayın ve tam satır güncellemesi yapın:
INSERT INTO test1 (a, b, c)
SELECT d, e, f FROM test2
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
Varsayılan değerlere sahip sütunlarDO UPDATEtarafından güncellenmez, bu da performansı düşürür. SQL aracılığıyla InsertOrReplace uygulamak içinnulldeğeriniVALUESlistesinde açıkça iletin. Flink ve Data Integration gibi araçlar, eksik sütunlar içinnulldeğerini otomatik olarak ekler.
Sınırlamalar
ON CONFLICTyan tümcesi tüm birincil anahtar sütunlarına başvurmalıdır.-
Hologres Yüksek QPS Motoru (HQE),
INSERT ON CONFLICTişlemini yürüttüğünde işlem sırası garanti edilmez; ilk-kazanır ve son-kazanır semantikleri desteklenmez. Davranış herhangi-birini-tut (keep-any) şeklindedir. Kaynaktaki yinelenen satırlarda son-kazanır (keep-last) davranışını zorlamak için aşağıdaki ayarı yapın:set hg_experimental_affect_row_multiple_times_keep_last = on; -
Kaynak veriler yinelenen satır içermemelidir. PostgreSQL semantiği,
VALUESlistesindeki veya kaynak sorgusundaki her satırın benzersiz olmasını gerektirir. Kaynakta yinelenenler varsa (örneğin, aynı birincil anahtara sahip iki satır döndüren birSELECTalt sorgusundan) ifade başarısız olur. Bunu önlemek içinON CONFLICTyan tümcesinden önce kaynağı yinelmesiz hale getirin:-- Deduplicate the source with a subquery before upserting INSERT INTO target_table (a, b, c) SELECT a, MAX(b), MAX(c) FROM source_table GROUP BY a ON CONFLICT (a) DO UPDATE SET (a, b, c) = ROW(excluded.*);
Örnekler
Test tablosunu hazırlama
BEGIN;
CREATE TABLE test1 (
a int NOT NULL PRIMARY KEY,
b int,
c int
);
COMMIT;
INSERT INTO test1 VALUES (1, 2, 3);
Aşağıdaki örnekler birbirinden bağımsızdır. Her biri yukarıdaki başlangıç durumundan başlar.
InsertOrIgnore — çakışma durumunda atla
Yinelenen bir birincil anahtar varsa gelen satır reddedilir.
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
ON CONFLICT (a)
DO NOTHING;
Sonuç:
a | b | c
1 | 2 | 3 -- unchanged
InsertOrUpdate — belirli sütunları güncelleme
Yalnızca SET içinde listelenen sütunlar güncellenir. Listelenmeyen sütunlar mevcut değerlerini korur.
-- Partial-column update: only b is updated, c keeps its value
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
ON CONFLICT (a)
DO UPDATE SET b = excluded.b;
Sonuç:
a | b | c
1 | 1 | 3 -- c unchanged
InsertOrUpdate — tam satır güncellemesi
İki eşdeğer form:
-- Method 1: list all columns explicitly
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
ON CONFLICT (a)
DO UPDATE SET b = excluded.b, c = excluded.c;
-- Method 2: use ROW(excluded.*) shorthand
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
Sonuç:
a | b | c
1 | 1 | 1
InsertOrReplace — eksik sütunlar için null ile üzerine yazma
Tüm satırı değiştirmek ve eksik sütunları null ile doldurmak için VALUES listesinde null değerini açıkça iletin.
INSERT INTO test1 (a, b, c) VALUES (1, 1, null)
ON CONFLICT (a)
DO UPDATE SET b = excluded.b, c = excluded.c;
Sonuç:
a | b | c
1 | 1 | \N
Başka bir tablodan upsert işlemi
-- Prepare source table
CREATE TABLE test2 (
d int NOT NULL PRIMARY KEY,
e int,
f int
);
INSERT INTO test2 VALUES (1, 5, 6);
-- Replace rows in test1 with matching rows from test2
INSERT INTO test1 (a, b, c)
SELECT d, e, f FROM test2
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
Sonuç:
a | b | c
1 | 5 | 6
Sütunları yeniden eşlemek için (örneğin, test2.e test1.c'yi ve test2.f test1.b'yi günceller):
INSERT INTO test1 (a, b, c)
SELECT d, e, f FROM test2
ON CONFLICT (a)
DO UPDATE SET (a, c, b) = ROW(excluded.*);
Sonuç:
a | b | c
1 | 6 | 5
Sorun giderme
Hata: duplicate key value violates unique constraint / Update row with Key multiple times
Belirtiler:
duplicate key value violates unique constraint
-- or --
Update row with Key (xxx)=(yyy) multiple times
Neden: Kaynak veriler yinelenen satırlar içeriyor. Aşağıdaki örnek hatayı çoğaltır:
-- This fails: the source contains (1, 2, 3) twice
INSERT INTO test1 VALUES (1, 2, 3), (1, 2, 3)
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
-- ERROR: internal error or constraint violation
Hata sonrası tablo durumu: test1 değişmez.
Çözüm: Yinelenen kaynak satırları otomatik olarak çözmek için keep-last bayrağını ayarlayın:
set hg_experimental_affect_row_multiple_times_keep_last = on;
Alternatif olarak, upsert işleminden önce kaynağı yinelmesiz hale getirin (bkz. Sınırlamalar).
Hata: süresi dolmuş TTL nedeniyle yinelenen anahtar
Neden: Bir kaynak tabloda time to live (TTL) yapılandırılmıştır. TTL süresi dolduktan sonra eski satırlar hemen temizlenmeyebilir ve kaynakta yinelenen birincil anahtarlar kalabilir.
Çözüm: Hologres V1.3.23 sürümünden itibaren, süresi dolmuş bir TTL nedeniyle oluşan yinelenen birincil anahtar satırlarını kaldırmak için aşağıdaki komutu kullanabilirsiniz. Varsayılan ilke keep-last'tir. Bu komut yalnızca Hologres V1.3.23 ve sonraki sürümlerde kullanılabilir; örneğiniz daha eski bir sürümse önce yükseltme yapın.
Prensip olarak birincil anahtarlar yinelenmemelidir. Bu komut yalnızca süresi dolmuş bir TTL nedeniyle oluşan yinelenen PK'ları temizler, genel PK yinelenmesini değil.
call public.hg_remove_duplicated_pk('<schema>.<table_name>');
Örnek:
BEGIN;
CREATE TABLE tbl_1 (a int NOT NULL PRIMARY KEY, b int, c int);
CREATE TABLE tbl_2 (d int NOT NULL PRIMARY KEY, e int, f int);
CALL set_table_property('tbl_2', 'time_to_live_in_seconds', '300');
COMMIT;
INSERT INTO tbl_1 VALUES (1, 1, 1), (2, 3, 4);
INSERT INTO tbl_2 VALUES (1, 5, 6);
-- After 300 seconds, insert a row with the same primary key into tbl_2.
INSERT INTO tbl_2 VALUES (1, 3, 6);
-- This fails: tbl_2 now has duplicate primary keys caused by TTL expiry.
INSERT INTO tbl_1 (a, b, c)
SELECT d, e, f FROM tbl_2
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
-- ERROR: internal error: Duplicate keys detected when building hash table.
-- Clean up duplicate primary keys in tbl_2, then retry.
call public.hg_remove_duplicated_pk('tbl_2');
-- The import now succeeds.
INSERT INTO tbl_1 (a, b, c)
SELECT d, e, f FROM tbl_2
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
Hata: out-of-memory (OOM)
Belirti:
Total memory used by all existing queries exceeded memory limitation
Neden: Örneğin büyük hacimli bir yazma görevi için yeterli belleği yoktur.
Çözüm:
Görevi sunucusuz kaynaklara yönlendirmek ve ekstra örnek kapasitesi ayırmadan OOM riskini azaltmak için Serverless Computing (Hologres V2.1.17+) kullanın.
Yaygın OOM hatalarını giderme bölümündeki adımları izleyin.
Sonraki adımlar
Temel alınan güncelleme mekanizmasını anlamak için UPDATE konusuna bakın.
Büyük yazma işlerini sunucusuz kaynaklara yönlendirmek için (Hologres V2.1.17+) Serverless Computing'a genel bakış konusuna bakın.
Data Integration'da yazma çakışma ilkesini yapılandırmak için Hologres Writer konusuna bakın.