日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

INSERT ON CONFLICT(UPSERT)

本文為您介紹在Hologres中INSERT ON CONFLICT語句的用法。

應用場景

INSERT ON CONFLICT命令適用于通過SQL方式導入數據的場景。

使用數據集成或Flink寫入數據時,如果需要對主鍵重復的行數據執行更新或跳過操作,則需進行如下配置:

  • 通過DataWorks的數據集成導入數據。

    數據集成已內置INSERT ON CONFLICT功能,該功能的實現原理請參見Hologres Writer。同時,您需要進行如下配置:

    • 離線同步數據時,寫入沖突策略選擇忽略(Ignore)或者更新(Replace)

    • 實時同步數據時,寫入沖突策略選擇忽略(Ignore)或者更新(Replace)

    說明

    同步數據時,Hologres的表均需要設置主鍵,才能更新數據。

  • 通過Flink寫入數據。

    通過Flink寫入數據默認寫入沖突策略使用InsertOrIgnore(保留首次出現的數據,忽略后續所有數據),但是需要您在Hologres建表時設置主鍵。詳情請參見Flink全托管概述如果使用ctas語法,則寫入沖突策略默認為InsertOrUpdate(替換部分已有數據)。

命令介紹

INSERT ON CONFLICT語句用于在指定列插入某行數據時,如果主鍵存在重復的行數據,則對該數據執行更新或跳過操作,實現UPSERT(INSERT OR UPDATE)的效果。INSERT ON CONFLICT的語法格式如下。

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 ]

參數說明如下表所示。

參數

描述

table_name

插入數據的目標表名稱。

alias

別名。目標表的替代名稱。

column_name

目標表中目標列名稱。

DO NOTHING

InsertOrIgnore,即在指定列插入某行數據時,如果主鍵存在重復的行數據,則對該數據執行跳過操作。

DO UPDATE

InsertOrUpdate,即在指定列插入某行數據時,如果主鍵存在重復的行數據,則對該數據執行更新操作。

存在如下情況:

  • 更新全部列:全部列的數據都更新,即整行更新。

  • 更新部分列:即局部列更新,缺失的列不更新。

  • 如果要實現InsertOrReplace的效果,同時缺失的列補null,需要手動在值內傳null,見下方使用示例。

  • 重要
    • 當列中有默認(default)值時,DO UPDATE不更新有默認值的列,性能會比較低。

    • 通過SQL(INSERT ON CONFLICT)實現的InsertOrReplace,缺失的列補null,需要在insert的值內傳null;如果是使用Flink、數據集成等方式,選擇InsertOrReplace會自動補null

expression

對應列執行的相關表達式,您可以參考Postgres來設置表達式,詳情請參見INSERT ON CONFLICT

常用表達式 b=excluded.b,或者(a, b, c) = ROW (excluded.*)簡化表達,等式左側表示要被更新的字段,等式右側表示插入的表達式,即values部分的值,或者select表達式,excluded是對插入表達式的別名,不是寫入源頭表的別名。例如,column_name = excluded.column_namecolumn_name為插入數據至目標表指定列的列名稱,假設column_name為目標表的第N列,則excluded.column_name為插入表達式的第N列,當使用excluded.*時,表示選擇所有列,列的順序為插入表達式中列的順序,需要保證插入目標列的順序與被寫入表的DDL順序一致。

技術原理

INSERT ON CONFLICT的技術實現原理同UPDATE,詳情請參見UPDATE。不同表存儲格式(行存、列存、行列共存)在更新時的細節處理會略有不同,這就導致不同存儲模式的表在更新時,性能會有不同。而根據業務的需求,INSERT ON CONFLICT又可以分為InsertOrIgnoreInsertOrReplaceInsertOrUpdate,三者的具體區別如下:

更新模式

說明

InsertOrIgnore

寫入時忽略更新,結果表有主鍵,實時寫入時如果主鍵重復,丟棄后到的數據,通過insert on conflict do nothing實現。

InsertOrUpdate

寫入更新,結果表有主鍵,實時寫入時如果主鍵重復,按照主鍵更新。分為整行更新和部分列更新,部分列更新指如果寫入的一行數據不包含所有列,缺失的列不更新。通過insert on conflict do update實現。

InsertOrReplace

寫入覆蓋,結果表有主鍵,實時寫入時如果主鍵重復,按照主鍵更新。如果寫入的一行數據不包含所有列,缺失的列的數據補Null,需要通過insert on conflict do update和手動補Null值一起實現。

根據UPDATE的原理,當表設置不同的存儲格式時,不同UPDATE模式下的更新性能如下:

  • 列存表不同寫入模式的性能排序如下。

    • 結果表無主鍵性能最高。

    • 結果表有主鍵時:InsertOrIgnore > InsertOrReplace >= InsertOrUpdate(整行)> InsertOrUpdate(部分列)

  • 行存表不同寫入模式的性能排序如下。

    InsertOrReplace = InsertOrUpdate(整行)>= InsertOrUpdate(部分列) >= InsertOrIgnore

使用限制

  • INSERT ON CONFLICT語句的條件必須包含所有主鍵。

  • Hologres HQE在執行INSERT ON CONFLICT時,本身不會保序(保證順序),因此不能實現keep first、keep last的效果,都是keep any。但在實際應用中,如果數據源有主鍵重復數據需要去重,建議使用keep last,命令如下:

    --保留重復數據的最后一條數據
    set hg_experimental_affect_row_multiple_times_keep_last = on;

使用示例

  • INSERT ON CONFLICT語句的示例用法:

    說明

    Hologres從V2.1.17版本起支持Serverless Computing能力,針對大數據量離線導入、大型ETL作業、外表大數據量查詢等場景,使用Serverless Computing執行該類任務可以直接使用額外的Serverless資源,避免使用實例自身資源,無需為實例預留額外的計算資源,顯著提升實例穩定性、減少OOM概率,且僅需為任務單獨付費。Serverless Computing詳情請參見Serverless Computing概述,Serverless Computing使用方法請參見Serverless Computing使用指南

    1. 準備表和數據:

      begin ;
      create table test1 (
          a int NOT NULL PRIMARY KEY,
          b int,
          c int
      );
      commit ;
      
      insert into test1 values (1,2,3);
      
    2. 不同場景下的使用示例:

      說明

      下面的每個場景示例結果不相互依賴,沒有順序關系,都是基于上述已創建的表和數據的結果。

      • 場景1:實現InsertOrIgnore,即主鍵重復不更新。

        INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
        ON CONFLICT (a)
        DO NOTHING;
        
        --更新后test1表的數據為:
        a	b	c
        1	2	3
      • 場景2:實現InsertOrUpdate的整行更新,可以通過如下兩種方式實現。

        • 方式1:在SET..EXCLUDED中列出所有的列。

          INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
          ON CONFLICT (a)
          DO UPDATE SET b = EXCLUDED.b, c = EXCLUDED.c;
          
          --更新后test1表的數據為:
          a	b	c
          1	1	1
        • 方式2:使用ROW(EXCLUDED.*)代表更新所有列。

          INSERT INTO test1 (a, b, c)VALUES (1, 1, 1)
          ON CONFLICT (a)
          DO UPDATE SET (a,b,c) = ROW(EXCLUDED.*);
          
          --更新后test1表的數據為:
          a	b	c
          1	1	1
      • 場景3:實現InsertOrUpdate的部分列更新,即只更新指定列,缺失的列不更新。

        --要實現部分列更新的效果,需要在set后列出想要更新的列
        INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
        ON CONFLICT (a)
        DO UPDATE SET b = EXCLUDED.b;
        
        --表中c列不更新,更新后test1表的數據為:
        a	b	c
        1	1	3
      • 場景4:實現InsertOrReplace,即整行覆蓋,如果有缺失的列,缺失的列補null。

        --如果要實現InsertOrReplace,且缺失的列補null,則需要在insert的值中手動補null。
        INSERT INTO test1 (a, b,c) VALUES (1, 1,null)
        ON CONFLICT (a)
        DO UPDATE SET b = EXCLUDED.b,c = EXCLUDED.c;
        
        --更新后test1表的數據為:
        a	b	c
        1	1	\N
      • 場景5:從另外一張test2表更新test1表數據。

        --準備test2表和數據
        CREATE TABLE test2 (
            d int NOT NULL PRIMARY KEY,
            e int,
            f int
        );
        INSERT INTO test2 VALUES (1, 5, 6);
        
        
        --將test2整表替換test1表相同主鍵的行
        INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET
        (a,b,c) = ROW (excluded.*);
        
        --更新后test1表數據如下:
        a	b	c
        1	5	6
        
        --將test2整表替換test1表相同主鍵的行,但調整了更新映射關系,即test2的e列更新到c列,f列更新到b列
        INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET
        (a,c,b) = ROW (excluded.*);
        --更新后test1表數據如下:       
        a	b	c
        1	6	5
  • 行存表INSERT ON CONFLICT語句的優化:

    Hologres對行存表的更新場景實行了優化,建議您在使用時將UPDATE列的順序與INSERT的順序保持一致,并且更新為整行更新。

    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.*)

常見報錯

  • 問題現象

    對數據源執行INSERT ON CONFLICT語句時出現如下兩種報錯其中一個。

    • 報錯一:duplicate key value violates unique constraint

    • 報錯二:Update row with Key (xxx)=(yyy) multiple times

    • 報錯三(OOM問題):Total memory used by all existing queries exceeded memory limitation

  • 問題原因一:數據源存在重復數據。

    Hologres兼容PostgreSQL,使用的也是標準PostgreSQL語法。在標準的PostgreSQL語義中,對數據源執行INSERT ON CONFLICT語句時,數據源不能包含重復數據,如果包含重復數據則會產生上述報錯。

    說明

    數據源重復是指待插入的數據中包含重復數據,不是指待插入的數據與表里的數據重復。

    使用INSERT ON CONFLICT語句插入數據時包含重復數據,示例語句如下。

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

    解決方法:

    如果數據源包含重復數據,可以配置如下參數,保留重復數據的最后一條數據:

    set hg_experimental_affect_row_multiple_times_keep_last = on;
  • 問題原因二:數據源因TTL過期出現重復數據。

    數據源中有表設置過表數據生命周期(TTL),表中有部分數據已經過了TTL,因TTL不是準確的時間,導致過期的數據未被清理,導入時主鍵(PK)數據重復,從而出現報錯。

    解決方法:

    Hologres從 V1.3.23版本開始,通過以下命令能快速修正因TTL過期PK重復的數據。執行該命令后,系統會將該表PK重復的數據清理掉,清理策略默認為Keep Last即保留重復PK中最后一條寫入的PK數據,其余重復PK數據進行清理。

    說明
    • 原則上來說PK不會出現重復數據,因此該命令僅清理因TTL導致PK重復的數據。

    • 該命令僅Hologres V1.3.23及以上版本使用,若實例版本較低,請升級實例。

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

    使用示例:假設有兩個表,tbl_1為目標表,tbl_2為源表且配置了TTL,時間設置為300s。將tbl_2的數據整行更新至tbl_1,因TTL過期后,tbl_2的主鍵重復,導致報錯。

    
    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);
    --過300s后再向tbl_2插入數據
    INSERT INTO tbl_2 VALUES (1, 3, 6);
    
    --將tbl_2整表替換tbl_1表相同主鍵的行,PK因ttl重復了導致更新報錯
    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.
    
    --guc清理tbl_2的PK重復數據,策略為keep last,
    call public.hg_remove_duplicated_pk('tbl_2');
    
    --再重新導入tbl_1數據,數據導入成功
  • 問題原因三:實例本身內存資源不足,無法支撐本次大數據量寫入任務。

    解決方法:

    • 推薦使用Hologres Serverless Computing能力執行本次大數據量寫入任務。Hologres從V2.1.17版本起支持Serverless Computing能力,針對大數據量離線導入、大型ETL作業、外表大數據量查詢等場景,使用Serverless Computing執行該類任務可以直接使用額外的Serverless資源,避免使用實例自身資源,無需為實例預留額外的計算資源,顯著提升實例穩定性、減少OOM概率,且僅需為任務單獨付費。Serverless Computing詳情請參見Serverless Computing概述,Serverless Computing使用方法請參見Serverless Computing使用指南

    • 參考OOM常見問題排查指南中的方法處理。