一、业务场景
某客户上线一段时间后,日志中出现大量主键冲突的日志,并且出现数据库繁忙。
ERROR: duplicate key value violates unique constraint “visit_workrecord_pkey”
Detail: Key (recordid)=(1105661718883) already exists.
问题: 此类日志会大量出现。
二、UPSET 场景演示
如果出现这种约束冲突后,该如何处理,在PostgreSQL中UPSET特性是指INSERT ... ON CONFLICT UPDATE,专门用来处理这种数据冲突的情况。
-- 自定义一张用户登录日志表
CREATE TABLE user_logins (
user_name VARCHAR(200) PRIMARY KEY,
login_cnt INT4,
last_login_time TIMESTAMP(0) WITHOUT TIME ZONE
);
插入重复数据后报错
INSERT INTO user_logins (user_name,login_cnt) VALUES
('frances',1),('mate',2),('frances',1);
2.1 冲突时更新
-- 先插入一条
INSERT INTO user_logins (user_name,login_cnt) VALUES
('frances',1);
-- 重复插入
INSERT INTO user_logins (user_name,login_cnt) VALUES
('mate',2),('frances',1)
ON conflict(user_name)
DO UPDATE SET
login_cnt = user_logins.login_cnt + EXCLUDED.login_cnt,last_login_time = now();
ON CONFLICT() 定义冲突
DO UPDATE SET 冲突动作
内置表 EXCLUDED
批量操作,将三条数据批量操作时,会报错
在这里插入图片描述
在SQL标准中,sql merge也有同样的问题,因为一次请求中对行的处理,顺序是不固定的。数据库不知道应该以哪条为最后需要保留的
标签 PostgreSQL , insert into on conflict , merge insert 背景 使用insert into on conflict 合并插入,如果一条SQL语句中,对一个KEY(冲突键,或冲突约束)多次发生冲突时,会报错。
2.2 冲突时不做任何操作
在发生冲突的时候不做任何处理。
select * from user_logins
-- TRUNCATE TABLE user_logins;
-- INSERT INTO user_logins (user_name,login_cnt) VALUES ('frances',1);
INSERT INTO user_logins (user_name,login_cnt) VALUES
('mate',2),('frances',1)
ON conflict(user_name)
DO NOTHING ;
三、如果不存在则插入,存在则更新
需要有一个唯一键
3.1 MySQL 版本
MySQL语法支持如果数据存在则更新,不存在则插入,首先判断数据存在还是不存在的那个字段要设置成unique索引。
SELECT * FROM user_logins;
CREATE TABLE user_logins (
user_name VARCHAR(200) PRIMARY KEY,
login_cnt INT4,
last_login_time date
);
-- 执行下面语句两次查看结果
INSERT INTO user_logins (user_name,login_cnt,last_login_time) VALUES ('frances',3,now())
ON DUPLICATE KEY UPDATE login_cnt= 4,last_login_time= '2019-04-13';
3.2 PostgreSQL版本
SELECT * FROM user_logins;
CREATE TABLE user_logins (
user_name VARCHAR(200) PRIMARY KEY,
login_cnt INT4,
last_login_time date
);
-- 执行两次看结果
INSERT INTO user_logins (user_name,login_cnt,last_login_time) VALUES ('frances',3,now())
ON conflict(user_name)
DO UPDATE SET
login_cnt = 4,last_login_time = now();