• Postgresql源码(66)insert on conflict语法介绍与内核执行流程解析


    1 语法介绍

    insert on conflict语法实现了upsert的功能,即在插入发生主键冲突、或唯一约束冲突时,执行on conflict后面的语句,将insert变成update或do nothing避免报错。

    语法手册:https://www.postgresql.org/docs/current/sql-insert.html

    测试用例:

    drop table decoding_test;
    CREATE TABLE decoding_test(x integer primary key, y text);
    
    postgres=# select * from decoding_test;
     x  | y 
    ----+---
     12 | 9
    
    postgres=# INSERT INTO decoding_test(x,y) values(12,9) on conflict (x) do nothing;
    INSERT 0 1
    
    postgres=# select * from decoding_test;
     x  | y 
    ----+---
     12 | 9
    
    -- 没有报主键冲突,结果上看插入没有效果。
    postgres=# INSERT INTO decoding_test(x,y) values(12,9) on conflict (x) do nothing;
    INSERT 0 0
    
    postgres=# select * from decoding_test;
     x  | y 
    ----+---
     12 | 9
    (1 row)
    
    postgres=# INSERT INTO decoding_test(x,y) values(101,20) on conflict (x) do update set y=EXCLUDED.y;
    INSERT 0 1
    postgres=# 
    postgres=# select * from decoding_test;
      x  | y  
    -----+----
      12 | 9
     101 | 20
     
    -- 插入时发生主键冲突,执行后面的update语句,将y更新为400,EXCLUDED表示准备要新插入的这一行数据。
    postgres=# INSERT INTO decoding_test(x,y) values(101,400) on conflict (x) do update set y=EXCLUDED.y;
    INSERT 0 1
    postgres=# select * from decoding_test;
      x  |  y  
    -----+-----
      12 | 9
     101 | 400
    (2 rows)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    2 内核执行流程

    注意:后面提到的speculative insert等价与insert on conflict语法

    2.1 从执行流程观察speculative insert

    执行流程:

    • spec insert的执行流程和普通insert是分开的,走两个分支。
    • spec比较特殊的就是有重试机制,即:
      • 在第一次检查如果没发现有唯一键冲突,正常是可以直接insert的。
      • 但由于无锁检查,可能在真正insert时又发生了唯一键冲突(前面检查完了,其他并发insert一条冲突数据)
      • 那么这时xlog中已经有一条成功的insert了,需要再后面加一条delete(图中第四步冲突发生了)。
        请添加图片描述

    2.2 从日志角度观察speculative insert

    • INSERT INTO decoding_test(x,y) values(12,9) on conflict (x) do nothing;
      • 情况一:插入成功
        • heap_insert,生成XLOG_HEAP_INSERT日志。
        • heap_finish_speculative,生成XLOG_HEAP_CONFIRM日志。
      • 情况二:插入失败
        • 不生成日志
      • 情况三:插入时还没有冲突,但其他进程并发插入冲突行(并发冲突位置在后面分析)
        • heap_insert,生成XLOG_HEAP_INSERT日志。
        • heap_abort_speculative,生成XLOG_HEAP_DELETE日志。
    • INSERT INTO decoding_test(x,y) values(20,9) on conflict (x) do update set y=100;
      • 插入成功
        • heap_insert,生成XLOG_HEAP_INSERT日志。
        • heap_finish_speculative,生成XLOG_HEAP_CONFIRM日志。
      • 更新成功:转换为update语句执行
        • log_heap_update,生成XLOG_HEAP_HOT_UPDATE日志。
      • 插入时还没有冲突,但其他进程并发插入冲突行(并发冲突位置在后面分析)
        • heap_insert,生成XLOG_HEAP_INSERT日志。
        • heap_abort_speculative,生成XLOG_HEAP_DELETE日志。

    所以从日志中可能看到3种情况:

    情况一: 第一条XLOG_HEAP_INSERT      第二条XLOG_HEAP_CONFIRM
    情况二: 第一条XLOG_HEAP_INSERT      第二条XLOG_HEAP_DELETE
    情况三: 第一条XLOG_HEAP_HOT_UPDATE
    
    • 1
    • 2
    • 3

    下一篇继续介绍这几种日志被逻辑复制解析后的情况。

  • 相关阅读:
    @Value的用法
    2022年中科磐云——服务器内部信息获取 解析flag
    【电路笔记】-诺顿定理(Norton‘s Theorem)
    Vscode远程调试及gdbserver配置
    无法对wsl-docker-data本身的unbutu镜像扩容操作
    Webpack性能优化 SplitChunksPlugin的使用详解
    推荐10款3DMax样条线相关的神仙插件
    聚苯乙烯PS彩色胶乳微球:红色/蓝色/黑色/绿色胶乳微球介绍和制备方法
    Rust生态系统:探索常用的库和框架
    天才在左,疯子在右读书笔记 -- 高铭著
  • 原文地址:https://blog.csdn.net/jackgo73/article/details/126145497