您的位置:首页 > 数据库 > MySQL

mysql的insert on duplicate与replace into的一些研究

2015-08-21 15:04 666 查看
mysql的innodb引擎是以主键为聚集索引的表结构,在日常的开发运维中经常会遇到duolicate key(重复主键)的报错

为了避免这一问题,mysql提供了replace into与insert into onduplicate的语法,但这两个语法在实现上是不同的

实验如下:

mysql> show create table wzy;

+-------+------------------------------------------------------------------------------------------------------------------------------------+

| Table | Create Table |

+-------+------------------------------------------------------------------------------------------------------------------------------------+

| wzy | CREATE TABLE `wzy` (

`id` int(11) NOT NULL,

`mark` int(11) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

+-------+------------------------------------------------------------------------------------------------------------------------------------+

1 row in set

mysql> desc wzy;

+-------+---------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+-------+---------+------+-----+---------+-------+

| id | int(11) | NO | PRI | NULL | |

| mark | int(11) | YES | | NULL | |

+-------+---------+------+-----+---------+-------+

2 rows in set

以上是这次作为测试的表结构

mysql> desc wzy_test;

+-------+---------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+-------+---------+------+-----+---------+-------+

| id | int(11) | NO | PRI | NULL | |

+-------+---------+------+-----+---------+-------+

1 row in set

这是用于批量插入做的辅助表

mysql> select count(*) from wzy_test;

+----------+

| count(*) |

+----------+

| 579 |

+----------+

1 row in set

可以看到辅助表中有579条数据

向测试表wzy中插入300条,并mark为1

mysql> replace into wzy(id,mark)

select id,1 from wzy_test limit 300;

Query OK, 300 rows affected

Records: 300 Duplicates: 0 Warnings: 2

插入300条

我们此时将整个579条都使用replace into进去

mysql> replace into wzy(id,mark)

select id,2 from wzy_test;

Query OK, 879 rows affected

Records: 579 Duplicates: 300 Warnings: 1

可见一共操作了879行数据,即579+300,之前插入的300条都进行了删除,再插入

清空wzy

mysql> truncate table wzy;

Query OK, 0 rows affected

同样构造300条进wzy

mysql> replace into wzy(id,mark)

select id,1 from wzy_test limit 300;

Query OK, 300 rows affected

Records: 300 Duplicates: 0 Warnings: 2

这次使用insert into duplicate插入全部579条

mysql> insert into wzy(id,mark)

select id,2 from wzy_test

on DUPLICATE key UPDATE mark=2;

Query OK, 879 rows affected

Records: 579 Duplicates: 300 Warnings: 1

一共影响了879条,也是579+300

这次是全部重复数据进行插入

mysql> replace into wzy(id,mark)

select id,2 from wzy_test;

Query OK, 579 rows affected

Records: 579 Duplicates: 0 Warnings: 1

可见replace into要操作全部数据,哪怕本身没有任何变化.

再来看insert into duplicate的场景

mysql> insert into wzy(id,mark)

select id,2 from wzy_test

on DUPLICATE key UPDATE mark=2;

Query OK, 0 rows affected

Records: 579 Duplicates: 0 Warnings: 1

没有影响哪怕一行数据!

总结分析:replace into的机制是发现重复主键的情况下,删除该行,再插入新的数据,而在数据一致的情况下,做了一个不变的操作,所以操作的行数只会比预计插入的量多,

insert into duplicate则是先对表中的数据与要插入的数据进行对比,在不一样的场合,再进行操作,而这个操作就跟replace一样,先删除再插入

为了验证这一点,又进行了一点补充实验

mysql> insert into wzy(id,mark)

select id,2 from wzy_test limit 300

on DUPLICATE key UPDATE mark=3;

Query OK, 600 rows affected

Records: 300 Duplicates: 300 Warnings: 2

这里改变了mark的值,只用insert into duplicate更新前300条数据,总共影响600即为删300插300

mysql> insert into wzy(id,mark)

select id,2 from wzy_test limit 300

on DUPLICATE key UPDATE mark=2;

Query OK, 600 rows affected

Records: 300 Duplicates: 300 Warnings: 2

再将前300的mark值改回2,也是删300再插入300

mysql> insert into wzy(id,mark)

select id,2 from wzy_test limit 300

on DUPLICATE key UPDATE mark=2;

Query OK, 0 rows affected

Records: 300 Duplicates: 0 Warnings: 2

重复上次的操作,这次0 rows affected

总结:在使用insert on duplicate与replace into时,对不一致的数据2个方法采取了相同的方式,先删除再插入,而对于相同的数据,insert on duplicate只做了一次比较,没有操作,而replace into则有了一次不发生变化的操作,这个操作实际上还是要消耗性能的.

所以在这里推荐使用insert on duplicate的形式来处理重复主键的问题.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: