博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PostgreSQL merge insert(upsert/insert into on conflict) 如何区分数据是INSERT还是UPDATE
阅读量:6436 次
发布时间:2019-06-23

本文共 3960 字,大约阅读时间需要 13 分钟。

背景

使用insert into on conflict update语法,可以支持UPSERT的功能,但是到底这条SQL是插入的还是更新的呢?如何判断

通过xmax字段的值是否不为0,可以判断,如果是UPDATE,XMAX里面会填充更新事务号。

注意直接用UPDATE语句更新的话,XMAX会写入0,因为是新版本,而老版本上XMAX会填入更新事务号。

例子

1 insert on conflict
postgres=# create table t(id int primary key, info text, crt_time timestamp);
CREATE TABLE
postgres=# insert into t values (1,'test',now()) on conflict (id) do update set info=excluded.info,crt_time=excluded.crt_time returning xmax;

xmax

0

(1 row)

INSERT 0 1

postgres=# insert into t values (1,'test',now()) on conflict (id) do update set info=excluded.info,crt_time=excluded.crt_time returning xmax;

xmax

160369640

(1 row)

INSERT 0 1

postgres=# select xmin,xmax,* from t;

xmin xmax id info crt_time
160369640 160369640 1 test 2018-10-17 12:09:38.760926

(1 row)

postgres=# insert into t values (1,'test',now()) on conflict (id) do update set info=excluded.info,crt_time=excluded.crt_time returning xmax;

xmax

160369641

(1 row)

INSERT 0 1

postgres=# select xmin,xmax,* from t;

xmin xmax id info crt_time
160369641 160369641 1 test 2018-10-17 12:10:11.738691

(1 row)

postgres=# insert into t values (2,'test',now()) on conflict (id) do update set info=excluded.info,crt_time=excluded.crt_time returning xmax;

xmax

0

(1 row)

INSERT 0 1

postgres=# select xmin,xmax,* from t;

xmin xmax id info crt_time
160369641 160369641 1 test 2018-10-17 12:10:11.738691
160369642 0 2 test 2018-10-17 12:10:24.758745

(2 rows)

postgres=# select ctid,xmin,xmax,* from t;

ctid xmin xmax id info crt_time
(0,3) 160369641 160369641 1 test 2018-10-17 12:10:11.738691
(0,4) 160369642 0 2 test 2018-10-17 12:10:24.758745

(2 rows)

postgres=# insert into t values (2,'test',now()) on conflict (id) do update set info=excluded.info,crt_time=excluded.crt_time returning ctid,xmin,xmax,*;

ctid xmin xmax id info crt_time
(0,5) 160369643 160369643 2 test 2018-10-17 12:10:45.951351

(1 row)

INSERT 0 1

postgres=# select ctid,xmin,xmax,* from t;

ctid xmin xmax id info crt_time
(0,3) 160369641 160369641 1 test 2018-10-17 12:10:11.738691
(0,5) 160369643 160369643 2 test 2018-10-17 12:10:45.951351

(2 rows)

2 直接update
postgres=# update t set info='a' returning xmin,xmax,ctid,*;

xmin xmax ctid id info crt_time
160369644 0 (0,6) 1 a 2018-10-17 12:10:11.738691
160369644 0 (0,7) 2 a 2018-10-17 12:10:45.951351

(2 rows)

UPDATE 2

3 update 回滚
postgres=# begin;
BEGIN
postgres=# update t set info='a' returning xmin,xmax,ctid,*;

xmin xmax ctid id info crt_time
160369645 0 (0,8) 1 a 2018-10-17 12:10:11.738691
160369645 0 (0,9) 2 a 2018-10-17 12:10:45.951351

(2 rows)

UPDATE 2

postgres=# rollback;
ROLLBACK
postgres=# select ctid,xmin,xmax,* from t;

ctid xmin xmax id info crt_time
(0,6) 160369644 160369645 1 a 2018-10-17 12:10:11.738691
(0,7) 160369644 160369645 2 a 2018-10-17 12:10:45.951351

(2 rows)

4 delete 回滚
postgres=# begin;
BEGIN
postgres=# delete from t returning ctid,xmin,xmax,*;

ctid xmin xmax id info crt_time
(0,6) 160369644 160369646 1 a 2018-10-17 12:10:11.738691
(0,7) 160369644 160369646 2 a 2018-10-17 12:10:45.951351

(2 rows)

DELETE 2

postgres=# rollback;
ROLLBACK
postgres=# select ctid,xmin,xmax,* from t;

ctid xmin xmax id info crt_time
(0,6) 160369644 160369646 1 a 2018-10-17 12:10:11.738691
(0,7) 160369644 160369646 2 a 2018-10-17 12:10:45.951351

(2 rows)

小结
1、insert into on conflict do update,返回xmax不等于0,表示update,等于0表示insert。

2、直接update,并提交,提交的记录上xmax为0。

3、直接update,并回滚,老版本上的XMAX不为0,表示更新该行的事务号。

4、直接DELETE,并回滚,老版本上的XMAX不为0,表示删除该行的事务号。

ctid表示行号, xmin表示INSERT该记录的事务号,xmax表示删除该记录(update实际上是删除老版本新增新版本,所以老版本上xmax有值)的事务号。

参考

《Greenplum & PostgreSQL UPSERT udf 实现 - 2 batch批量模式》

《Greenplum & PostgreSQL UPSERT udf 实现 - 1 单行模式》

《PostgreSQL 多重含义数组检索与条件过滤 (标签1:属性, 标签n:属性) - 包括UPSERT操作如何修改数组、追加数组元素》

《HTAP数据库 PostgreSQL 场景与性能测试之 22 - (OLTP) merge insert|upsert|insert on conflict|合并写入》

《PostgreSQL upsert功能(insert on conflict do)的用法》

《PostgreSQL 如何实现upsert与新旧数据自动分离》

《[转载]postgresql 9.5版本之前实现upsert功能》

《upsert - PostgreSQL 9.4 pending patch : INSERT...ON DUPLICATE KEY IGNORE》

你可能感兴趣的文章
全新WiFi技术问世 更适合智能家庭和物联网
查看>>
开机慢 不换SSD如何提升Windows 10开机速度
查看>>
Android键盘面板冲突 布局闪动处理方案
查看>>
阿里云E-MapReduce 创建执行计划
查看>>
数据中心里的应急关机技术
查看>>
偏见为什么是数据科学领域的一个大问题
查看>>
SAS实现四十年连续增长,2015年全球营收达31.6亿美元
查看>>
日本社交餐厅评论服务平台Retty获1050万美元D轮融资
查看>>
未来两年内的九大信息安全威胁(三)
查看>>
界面按钮太多 聊天机器人都快被玩坏了
查看>>
果断收藏!六大主流大数据采集平台架构分析
查看>>
嵌入式产品开发设计需要考虑的问题总结
查看>>
物联网还是联网物?
查看>>
以持续集成工具实现DevOps之禅
查看>>
InfoComm China 2016“全球新产品发布活动” —— 汇聚众多革新设备及技术
查看>>
格瑞光电:智慧城市建设的引领者
查看>>
超级寒潮考验智慧城市万亿投资
查看>>
Radware发布2015-2016年全球应用及网络安全报告
查看>>
从“负电价”说起:谈谈德国新能源消纳的借鉴意义
查看>>
惠普大佬:未来30年四大趋势将推动科技产业发展
查看>>