全部产品
Search
文档中心

Hologres:INSERT ON CONFLICT (UPSERT)

更新时间:Feb 04, 2026

Dokumen ini menjelaskan cara menggunakan pernyataan INSERT ON CONFLICT di Hologres.

Skenario

Perintah INSERT ON CONFLICT cocok untuk skenario impor data menggunakan pernyataan SQL.

Saat menulis data menggunakan Data Integration atau Flink, Anda dapat mengonfigurasi pengaturan berikut untuk memperbarui atau melewatkan baris yang memiliki primary key duplikat:

  • Impor data menggunakan fitur Data Integration dari DataWorks.

    Data Integration memiliki fitur bawaan INSERT ON CONFLICT. Untuk informasi selengkapnya tentang cara kerja fitur ini, lihat Hologres Writer. Anda dapat mengonfigurasi pengaturan berikut:

    • Untuk sinkronisasi data offline, atur Write Conflict Policy menjadi Ignore atau Replace.

    • Untuk sinkronisasi data real-time, Anda dapat mengatur Write Conflict Policy menjadi Ignore atau Replace.

    Catatan

    Untuk memperbarui data selama sinkronisasi, Anda harus menetapkan primary key untuk tabel Hologres.

  • Tulis data menggunakan Flink.

    Saat menulis data menggunakan Flink, write conflict policy default adalah InsertOrIgnore. Kebijakan ini mengharuskan Anda menetapkan primary key untuk tabel Hologres dan menyimpan entri data pertama sambil mengabaikan semua entri duplikat berikutnya. Jika Anda menggunakan sintaksis ctas, write conflict policy default adalah InsertOrUpdate, yang menggantikan data yang ada.

Pengenalan perintah

Pernyataan INSERT ON CONFLICT menyisipkan satu baris data ke kolom yang ditentukan. Jika terdapat baris dengan primary key duplikat, pernyataan tersebut akan memperbarui baris yang ada atau melewatkan penyisipan, sehingga menyediakan fungsionalitas UPSERT (INSERT atau UPDATE). Sintaks pernyataan INSERT ON CONFLICT adalah sebagai berikut.

INSERT INTO <table_name> [ AS <alias> ] [ ( <column_name> [, ...] ) ]
    {  VALUES ( { <expression> } [, ...] ) [, ...] | <query> }
    [ ON CONFLICT [ conflict_target ] conflict_action ]

where conflict_target is pk

    ON CONSTRAINT constraint_name

and conflict_action is one of:

    DO NOTHING
    DO UPDATE SET { <column_name> = { <expression> } |
                    ( <column_name> [, ...] ) = ( { <expression> } [, ...] ) |
                  } [, ...]
              [ WHERE condition ]

Tabel berikut menjelaskan parameter-parameter tersebut.

Parameter

Deskripsi

table_name

Nama tabel tujuan tempat data dimasukkan.

alias

Alias. Ini adalah nama alternatif untuk tabel tujuan.

column_name

Nama kolom target di tabel tujuan.

DO NOTHING

InsertOrIgnore. Jika terdapat baris dengan primary key duplikat saat menyisipkan baris ke kolom yang ditentukan, penyisipan dilewati.

DO UPDATE

InsertOrUpdate. Jika terdapat baris dengan primary key duplikat saat menyisipkan baris ke kolom yang ditentukan, baris yang ada diperbarui.

Kasus-kasus berikut berlaku:

  • Perbarui semua kolom: Data di semua kolom diperbarui. Ini merupakan pembaruan seluruh baris.

  • Perbarui kolom tertentu: Hanya kolom yang ditentukan yang diperbarui. Kolom yang tidak disebutkan tidak diperbarui.

  • Untuk menerapkan operasi InsertOrReplace di mana kolom yang tidak disebutkan diisi dengan nilai null, Anda harus secara manual memberikan null dalam nilai-nilai yang dimasukkan. Untuk informasi selengkapnya, lihat contoh dalam topik ini.

  • Penting
    • Jika suatu kolom memiliki nilai default, DO UPDATE tidak memperbarui kolom tersebut. Hal ini mengakibatkan kinerja lebih rendah.

    • Untuk menerapkan operasi InsertOrReplace menggunakan pernyataan SQL (INSERT ON CONFLICT) di mana kolom yang tidak disebutkan diisi dengan null, Anda harus memberikan null dalam nilai insert. Jika Anda menggunakan tool seperti Flink atau Data Integration dan memilih InsertOrReplace, nilai null secara otomatis ditambahkan untuk kolom yang tidak disebutkan.

expression

Ekspresi yang akan dieksekusi untuk kolom yang sesuai. Anda dapat menyetel ekspresi ini dengan merujuk pada PostgreSQL.

Ekspresi umum meliputi b=excluded.b atau bentuk sederhana (a, b, c) = ROW (excluded.*). Sisi kiri persamaan menentukan kolom yang akan diperbarui. Sisi kanan menentukan ekspresi penyisipan, yaitu nilai dari klausa VALUES atau SELECT. Kata kunci excluded adalah alias untuk baris yang diusulkan untuk disisipkan, bukan alias untuk tabel sumber. Misalnya, pertimbangkan column_name = excluded.column_name. column_name adalah nama kolom di tabel tujuan. Jika column_name adalah kolom ke-N dari tabel tujuan, excluded.column_name mengacu pada kolom ke-N dari baris penyisipan yang diusulkan. Jika Anda menggunakan excluded.*, semua kolom dari baris penyisipan yang diusulkan dipilih. Urutan kolom harus sama dengan urutan dalam Data Definition Language (DDL) tabel tujuan.

Cara Kerja

Fitur INSERT ON CONFLICT bekerja serupa dengan pernyataan UPDATE. Untuk informasi selengkapnya, lihat UPDATE. Proses pembaruan sedikit berbeda tergantung pada format penyimpanan tabel—berorientasi baris, berorientasi kolom, atau hibrida baris-kolom—yang berdampak pada kinerja saat memperbarui tabel dengan format penyimpanan berbeda. Berdasarkan kebutuhan bisnis Anda, INSERT ON CONFLICT dapat dikategorikan sebagai InsertOrIgnore, InsertOrReplace, atau InsertOrUpdate. Tabel berikut menjelaskan perbedaannya.

Mode Pembaruan

Deskripsi

InsertOrIgnore

Mengabaikan pembaruan selama penulisan. Jika tabel sink memiliki primary key dan ditemukan primary key duplikat selama penulisan real-time, data yang datang belakangan dibuang. Ini diimplementasikan menggunakan insert on conflict do nothing.

InsertOrUpdate

Memperbarui data selama penulisan. Jika tabel sink memiliki primary key dan ditemukan primary key duplikat selama penulisan real-time, data diperbarui berdasarkan primary key. Mode ini mencakup pembaruan seluruh baris dan pembaruan kolom parsial. Dalam pembaruan kolom parsial, jika baris masuk tidak berisi semua kolom, kolom yang tidak disebutkan tidak diperbarui. Ini diimplementasikan menggunakan insert on conflict do update.

InsertOrReplace

Menimpa data selama penulisan. Jika tabel sink memiliki primary key dan ditemukan primary key duplikat selama penulisan real-time, data diperbarui berdasarkan primary key. Jika baris masuk tidak berisi semua kolom, kolom yang tidak disebutkan diisi dengan nilai null. Ini diimplementasikan menggunakan insert on conflict do update dan secara manual memberikan nilai null.

Berdasarkan cara kerja pernyataan UPDATE, kinerja pembaruan dalam mode yang berbeda bervariasi tergantung pada format penyimpanan tabel:

  • Kinerja mode penulisan berbeda untuk tabel berorientasi kolom diurutkan sebagai berikut:

    • Kinerja tertinggi jika tabel sink tidak memiliki primary key.

    • Jika tabel sink memiliki primary key: InsertOrIgnore > InsertOrReplace >= InsertOrUpdate (full row) > InsertOrUpdate (partial column).

  • Kinerja mode penulisan berbeda untuk tabel berorientasi baris diurutkan sebagai berikut:

    InsertOrReplace = InsertOrUpdate (full row) >= InsertOrUpdate (partial column) >= InsertOrIgnore.

Batasan

  • Kondisi dalam pernyataan INSERT ON CONFLICT harus mencakup semua primary key.

  • Saat Hologres High-QPS Engine (HQE) mengeksekusi pernyataan INSERT ON CONFLICT, urutan operasi tidak dijamin. Oleh karena itu, Anda tidak dapat mencapai semantik keep-first atau keep-last. Perilakunya adalah keep-any. Dalam praktiknya, jika sumber data berisi primary key duplikat yang perlu dihapus, Anda dapat menggunakan semantik keep-last dengan menjalankan perintah berikut:

    -- Simpan baris terakhir dari baris duplikat.
    set hg_experimental_affect_row_multiple_times_keep_last = on;

Contoh

  • Contoh penggunaan pernyataan INSERT ON CONFLICT:

    Catatan

    Hologres V2.1.17 dan versi yang lebih baru mendukung Serverless Computing. Untuk skenario seperti impor data offline berskala besar, pekerjaan extract, transform, and load (ETL) besar, dan kueri volume besar pada tabel eksternal, Anda dapat menggunakan Serverless Computing untuk mengeksekusi tugas-tugas tersebut. Fitur ini menggunakan sumber daya serverless tambahan alih-alih sumber daya instans Anda sendiri. Anda tidak perlu menyediakan sumber daya komputasi tambahan untuk instans Anda. Hal ini secara signifikan meningkatkan stabilitas instans, mengurangi kemungkinan error out-of-memory (OOM), dan Anda hanya dikenai biaya untuk setiap tugas individual. Untuk informasi selengkapnya tentang Serverless Computing, lihat Serverless Computing. Untuk informasi tentang cara menggunakan Serverless Computing, lihat Panduan penggunaan Serverless Computing.

    1. Persiapkan tabel dan data:

      begin ;
      create table test1 (
          a int NOT NULL PRIMARY KEY,
          b int,
          c int
      );
      commit ;
      
      insert into test1 values (1,2,3);
      
    2. Lihat contoh untuk skenario berbeda:

      Catatan

      Contoh skenario berikut bersifat independen satu sama lain. Mereka tidak berurutan dan semuanya didasarkan pada tabel dan data yang dibuat pada langkah sebelumnya.

      • Skenario 1: Terapkan operasi InsertOrIgnore. Jika terdapat primary key duplikat, baris tidak diperbarui.

        INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
        ON CONFLICT (a)
        DO NOTHING;
        
        -- Data dalam tabel test1 setelah pembaruan:
        a	b	c
        1	2	3
      • Skenario 2: Terapkan operasi InsertOrUpdate untuk pembaruan seluruh baris. Anda dapat menggunakan salah satu metode berikut:

        • Metode 1: Cantumkan semua kolom dalam klausa SET..EXCLUDED.

          INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
          ON CONFLICT (a)
          DO UPDATE SET b = EXCLUDED.b, c = EXCLUDED.c;
          
          -- Data dalam tabel test1 setelah pembaruan:
          a	b	c
          1	1	1
        • Metode 2: Gunakan ROW(EXCLUDED.*) untuk memperbarui semua kolom.

          INSERT INTO test1 (a, b, c)VALUES (1, 1, 1)
          ON CONFLICT (a)
          DO UPDATE SET (a,b,c) = ROW(EXCLUDED.*);
          
          -- Data dalam tabel test1 setelah pembaruan:
          a	b	c
          1	1	1
      • Skenario 3: Terapkan operasi InsertOrUpdate untuk pembaruan kolom parsial. Hanya kolom yang ditentukan yang diperbarui, dan kolom yang tidak disebutkan tidak diperbarui.

        -- Untuk melakukan pembaruan kolom parsial, cantumkan kolom yang ingin Anda perbarui setelah SET.
        INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
        ON CONFLICT (a)
        DO UPDATE SET b = EXCLUDED.b;
        
        -- Kolom c dalam tabel tidak diperbarui. Data dalam tabel test1 setelah pembaruan:
        a	b	c
        1	1	3
      • Skenario 4: Terapkan operasi InsertOrReplace. Ini menimpa seluruh baris. Jika kolom tidak disebutkan, kolom tersebut diisi dengan nilai null.

        -- Untuk menerapkan operasi InsertOrReplace di mana kolom yang tidak disebutkan diisi dengan null, Anda harus secara manual memberikan null dalam nilai insert.
        INSERT INTO test1 (a, b,c) VALUES (1, 1,null)
        ON CONFLICT (a)
        DO UPDATE SET b = EXCLUDED.b,c = EXCLUDED.c;
        
        -- Data dalam tabel test1 setelah pembaruan:
        a	b	c
        1	1	\N
      • Skenario 5: Perbarui data dalam tabel test1 dari tabel lain bernama test2.

        -- Persiapkan tabel test2 dan data.
        CREATE TABLE test2 (
            d int NOT NULL PRIMARY KEY,
            e int,
            f int
        );
        INSERT INTO test2 VALUES (1, 5, 6);
        
        
        -- Ganti baris dalam tabel test1 dengan baris dari tabel test2 yang memiliki primary key yang sama.
        INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET
        (a,b,c) = ROW (excluded.*);
        
        -- Data dalam tabel test1 setelah pembaruan:
        a	b	c
        1	5	6
        
        -- Ganti baris dalam tabel test1 dengan baris dari tabel test2 yang memiliki primary key yang sama, tetapi sesuaikan pemetaan pembaruan. Kolom e dari test2 memperbarui kolom c, dan kolom f dari test2 memperbarui kolom b.
        INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET
        (a,c,b) = ROW (excluded.*);
        -- Data dalam tabel test1 setelah pembaruan:       
        a	b	c
        1	6	5
  • Optimalisasi untuk pernyataan INSERT ON CONFLICT pada tabel berorientasi baris:

    Hologres mengoptimalkan pembaruan untuk tabel berorientasi baris. Untuk kinerja terbaik, pertahankan urutan kolom dalam klausa UPDATE konsisten dengan urutan dalam klausa INSERT dan lakukan pembaruan seluruh baris.

    INSERT INTO test1 (a, b, c) 
    SELECT
        d,e,f
    FROM
        test2
    ON CONFLICT (a)
        DO UPDATE SET
            a = excluded.a,
            b = excluded.b,
            c = excluded.c;
            
    INSERT INTO test1 (a, b, c)
    SELECT d,e,f FROM test2
    ON CONFLICT (a)
    DO UPDATE SET(a,b,c) = ROW (excluded.*)

Error umum

  • Gejala

    Salah satu dari tiga error berikut terjadi saat Anda mengeksekusi pernyataan INSERT ON CONFLICT pada sumber data:

    • Error 1: duplicate key value violates unique constraint.

    • Error 2: Update row with Key (xxx)=(yyy) multiple times.

    • Error 3 (masalah OOM): Total memory used by all existing queries exceeded memory limitation.

  • Penyebab 1: Sumber data berisi data duplikat.

    Hologres kompatibel dengan PostgreSQL dan menggunakan sintaks standar PostgreSQL. Menurut semantik standar PostgreSQL, sumber data tidak boleh berisi data duplikat saat Anda mengeksekusi pernyataan INSERT ON CONFLICT. Jika sumber data berisi data duplikat, salah satu error di atas akan terjadi.

    Catatan

    Data duplikat dalam sumber data berarti data yang akan dimasukkan berisi baris duplikat, bukan bahwa data yang akan dimasukkan memiliki duplikat di tabel tujuan.

    Contoh berikut menunjukkan pernyataan INSERT ON CONFLICT di mana data yang akan dimasukkan berisi baris duplikat:

    INSERT INTO test1 VALUES (1, 2, 3), (1, 2, 3)
    ON CONFLICT (a) 
    DO UPDATE SET (a, b, c) = ROW (excluded.*);

    Solusi:

    Jika sumber data berisi data duplikat, Anda dapat mengonfigurasi parameter berikut untuk menyimpan baris terakhir dari baris duplikat:

    set hg_experimental_affect_row_multiple_times_keep_last = on;
  • Penyebab 2: Sumber data berisi data duplikat karena masa hidup data (TTL) telah kedaluwarsa.

    Tabel dalam sumber data memiliki time to live (TTL) yang dikonfigurasi. Beberapa data dalam tabel telah melebihi TTL-nya. Karena pembersihan TTL tidak instan, data yang kedaluwarsa mungkin tidak segera dihapus. Hal ini dapat menyebabkan data primary key (PK) duplikat selama impor, yang mengakibatkan error.

    Solusi:

    Mulai dari Hologres V1.3.23, Anda dapat menggunakan perintah berikut untuk memperbaiki dengan cepat data PK duplikat yang disebabkan oleh TTL yang kedaluwarsa. Saat menjalankan perintah ini, sistem menghapus data PK duplikat dari tabel. Kebijakan pembersihan default adalah Keep Last, yang menyimpan baris terakhir yang ditulis di antara duplikat dan menghapus yang lainnya.

    Catatan
    • Secara prinsip, PK seharusnya tidak diduplikasi. Oleh karena itu, perintah ini hanya membersihkan PK duplikat yang disebabkan oleh TTL yang kedaluwarsa.

    • Perintah ini hanya tersedia di Hologres V1.3.23 dan versi yang lebih baru. Jika instans Anda menggunakan versi sebelumnya, Anda harus melakukan upgrade instans.

    call public.hg_remove_duplicated_pk('<schema>.<table_name>');

    Contoh: Asumsikan Anda memiliki dua tabel. tbl_1 adalah tabel tujuan, dan tbl_2 adalah tabel sumber dengan TTL 300s. Anda ingin memperbarui tbl_1 dengan semua data dari tbl_2. Setelah TTL berakhir, primary key duplikat muncul di tbl_2, yang menyebabkan error.

    
    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);
    -- Setelah 300s, masukkan data ke tbl_2 lagi.
    INSERT INTO tbl_2 VALUES (1, 3, 6);
    
    -- Ganti baris di tbl_1 dengan baris dari tbl_2 yang memiliki primary key yang sama. Pembaruan gagal karena PK duplikat yang disebabkan oleh TTL yang kedaluwarsa.
    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.*);
    -- Penyebab error: ERROR: internal error: Duplicate keys detected when building hash table.
    
    -- Gunakan perintah untuk membersihkan data PK duplikat di tbl_2. Kebijakannya adalah keep last.
    call public.hg_remove_duplicated_pk('tbl_2');
    
    -- Impor data ke tbl_1 lagi. Data berhasil diimpor.
  • Penyebab 3: Instans memiliki sumber daya memori yang tidak mencukupi untuk mendukung tugas penulisan volume besar.

    Solusi:

    • Gunakan fitur Serverless Computing dari Hologres untuk menjalankan tugas penulisan volume besar. Hologres V2.1.17 dan versi yang lebih baru mendukung Serverless Computing. Anda dapat menggunakan fitur ini untuk impor data offline berskala besar, pekerjaan ETL besar, dan kueri volume besar pada tabel eksternal. Serverless Computing menggunakan sumber daya serverless tambahan untuk menjalankan tugas-tugas ini alih-alih menggunakan sumber daya instans Anda. Pendekatan ini menghilangkan kebutuhan untuk menyediakan sumber daya komputasi tambahan untuk instans Anda. Pendekatan ini secara signifikan meningkatkan stabilitas instans dan mengurangi kemungkinan error OOM. Anda hanya dikenai biaya untuk setiap tugas individual. Untuk informasi selengkapnya, lihat Serverless Computing dan Panduan Serverless Computing.

    • Ikuti metode yang dijelaskan dalam Pemecahan masalah error OOM umum.