mysql duplicate key与replace into对比

Posted PacosonSWJTU

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql duplicate key与replace into对比相关的知识,希望对你有一定的参考价值。

【REDME】

有些业务场景如下:

对于数据已经存在的,则更新;否则新增;

怎么判定数据已经存在,通过主键或唯一索引来判断

业务场景:业务库的全局参数表的参数值的新增或更新就是 有则更细无则插入的常见业务场景


【1】2种实现方式

通常情况下,我们是先select,判断数据是否存在;若不存在,则新增,否则更新;

要完成这个小小功能,我们需要写3条sql,非常麻烦;

采用2种简单方式(只需要写1条sql):

  • 方式1, duplicate key, insert into ...... on duplicate key update ...
  • 方式2,replace into,


【1.1】duplicate key update

0. duplicate 官方文档翻译,参见   https://blog.csdn.net/PacosonSWJTU/article/details/120058725

1.duplicate顾名思义,有重复键则更新,否则插入

2.语法如下:

如果指定 ON DUPLICATE KEY UPDATE 子句并且要插入的行会导致 UNIQUE 索引或 PRIMARY KEY 中出现重复值,则会发生旧行的 UPDATE。 例如,如果列 a 声明为 UNIQUE 并包含值 1,则以下两个语句具有类似的效果:

    INSERT INTO t1 (a,b,c) VALUES (1,2,3)
      ON DUPLICATE KEY UPDATE c=c+1;
     
    UPDATE t1 SET c=c+1 WHERE a=1;

3.测试案例

-- 表结构
CREATE TABLE `my_cust_warn_tbl` (
  `rcrd_id` varchar(64) NOT NULL COMMENT '记录编号',
  `cust_num` varchar(50) NOT NULL COMMENT '客户号',
  `cust_name` varchar(50) DEFAULT '' COMMENT '客户姓名',
  `warn_times` int(11) DEFAULT NULL COMMENT '客户预警次数',
  `create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
  `last_modify_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '最后修改时间',
  PRIMARY KEY (`rcrd_id`),
  UNIQUE KEY `uni_cust_num` (`cust_num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='客户预警表'

注意: 使用duplicate语法的数据库表一定要设置唯一索引,以便于判断数据是否存在;

统计客户的预警次数,很显然就是有着更新,没有则新增;

INSERT INTO  
mybatis.my_cust_warn_tbl (rcrd_id, cust_num, cust_name, warn_times)
VALUES('hand_11', 'hand_11_custnum', 'hand_11_custname', 0)
on duplicate key update warn_times=warn_times+1, create_time = current_timestamp
;

第一次执行上述sql,由于 hand_11_cust 不存在,则返回条数是1;

 第二次执行SQL如下 (注意,第一次与第二次的sql不一样,主键不同,但客户号相同,客户号是唯一索引)

INSERT INTO  
mybatis.my_cust_warn_tbl (rcrd_id, cust_num, cust_name, warn_times)
VALUES('hand_11_2', 'hand_11_custnum', 'hand_11_custname', 0)
on duplicate key update warn_times=warn_times+1, create_time = current_timestamp
;

由于 hand_11_cust 已经存在,更新条数返回2;


【1.2】replace into

1.replace顾名思义,替换,有则先删除,后插入;没有则直接插入;

步骤为:

  • step1)delete 存在的记录(通过主键或唯一索引来判断);
  • step2)重新插入新值;

为了演示效果,我们新建了一个主键自增的数据库表;

drop table if exists my_cust_warn_autopk_tbl
; 
CREATE TABLE `my_cust_warn_autopk_tbl` (
  `rcrd_id` int primary key not null auto_increment COMMENT '记录编号',
  `cust_num` varchar(50) NOT NULL COMMENT '客户号',
  `cust_name` varchar(50) DEFAULT '' COMMENT '客户姓名',
  `warn_times` int(11) DEFAULT NULL COMMENT '客户预警次数',
  `create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
  `last_modify_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '最后修改时间',
  UNIQUE KEY `uni_cust_num` (`cust_num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='客户预警表(自增)'
;

2. 测试案例

REPLACE INTO  
mybatis.my_cust_warn_autopk_tbl (cust_num, cust_name, warn_times)
VALUES('hand_12_custnum', 'hand_12_custname', 0)
; 

因为之前没有存在的数据,故更新行数为1;

 刚刚插入的记录的主键值为1 ; 如下;

 接着, 我们把客户姓名字段设置为null看下; 发现更新行数为2

REPLACE INTO  
mybatis.my_cust_warn_autopk_tbl (cust_num, cust_name, warn_times)
VALUES('hand_12_custnum', null, 0)
;  

我们看下数据长什么样子:仅有一个 主键值为2的记录存在

很显然,因为存在客户号为 hand_12_custnum的记录,于是先删除了 主键为1的记录,然后再插入主键为2的记录,如下:

 当然了,通过两次sql的 create_time 也可以判断出 第2次replace是 删除旧记录,然后重新新增一条数据,而不是在旧记录上修改; 因为 两次的create_time 不一样


【2】 两者执行时间简单对比

show variables like "%pro%";
set profiling=1;
show profiles ; 

以上是关于mysql duplicate key与replace into对比的主要内容,如果未能解决你的问题,请参考以下文章

mysql duplicate key与replace into对比

MySQL的replace into 与insert into on duplicate key update

MySQL的replace into 与insert into on duplicate key update

mysql中的ON DUPLICATE KEY UPDATE

(主键策略)ON DUPLICATE KEY UPDATE(Mysql的使用)

insert into ... on duplicate key update 与 replace 区别