mysql replace into 的使用情況
阿新 • • 發佈:2018-12-14
replace into的存在的幾種情況
- 當表存在主鍵並且存在唯一鍵的時候
- 如果只是主鍵衝突
mysql> select * from auto;
+----+---+------+---------+
| id | k | v | extra |
+----+---+------+---------+
| 2 | 2 | 2 | extra 2 |
| 3 | 3 | 3 | extra 3 |
| 4 | 1 | 1-1 | NULL |
+----+---+------+---------+
3 rows in set (0.00 sec)
mysql>
mysql> show create table auto\G
*************************** 1. row ***************************
Table: auto
Create Table: CREATE TABLE `auto` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL,
`v` varchar(100) DEFAULT NULL,
`extra` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
這裡我們插入一條主鍵已經存在的4的資料
mysql> replace into auto(id,k)values(4,5);
Query OK, 2 rows affected (0.01 sec)
mysql> select * from auto;
+----+---+------+---------+
| id | k | v | extra |
+----+---+------+---------+
| 2 | 2 | 2 | extra 2 |
| 3 | 3 | 3 | extra 3 |
| 4 | 5 | NULL | NULL |
+----+---+------+---------+
3 rows in set (0.00 sec)
mysql> show create table auto \G
*************************** 1. row ***************************
Table: auto
Create Table: CREATE TABLE `auto` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL,
`v` varchar(100) DEFAULT NULL,
`extra` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
發現,auto_increment並沒有+1,而是針對原來的那一條id=4的記錄進行了update,因為沒有指定其他列(v,extra)的值,所以,update的時候都使用了預設值.
- 如果主鍵跟唯一鍵都衝突並且在同一行裡
mysql> select * from auto;
+----+---+------+---------+
| id | k | v | extra |
+----+---+------+---------+
| 2 | 2 | 2 | extra 2 |
| 3 | 3 | 3 | extra 3 |
| 4 | 5 | NULL | NULL |
| 5 | 6 | 6 | NULL |
+----+---+------+---------+
4 rows in set (0.00 sec)
mysql> show create table auto \G
*************************** 1. row ***************************
Table: auto
Create Table: CREATE TABLE `auto` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL,
`v` varchar(100) DEFAULT NULL,
`extra` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql>
mysql>
mysql> replace into auto(id,k,extra)values(5,6,77);
Query OK, 2 rows affected (0.01 sec)
mysql> select * from auto;
+----+---+------+---------+
| id | k | v | extra |
+----+---+------+---------+
| 2 | 2 | 2 | extra 2 |
| 3 | 3 | 3 | extra 3 |
| 4 | 5 | NULL | NULL |
| 5 | 6 | NULL | 77 |
+----+---+------+---------+
4 rows in set (0.00 sec)
mysql> show create table auto \G
*************************** 1. row ***************************
Table: auto
Create Table: CREATE TABLE `auto` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL,
`v` varchar(100) DEFAULT NULL,
`extra` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
我們發現,auto_increment也並沒有+1,而是針對原來的那一條id=6的記錄進行了update,因為沒有指定其他列(v)的值,所以,update的時候都v使用了預設值變成了null
- 如果主鍵跟唯一鍵都衝突不在同一行,對應2條記錄呢
我們來看下:
mysql> show create table auto \G
*************************** 1. row ***************************
Table: auto
Create Table: CREATE TABLE `auto` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL,
`v` varchar(100) DEFAULT NULL,
`extra` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> select * from auto;
+----+---+------+---------+
| id | k | v | extra |
+----+---+------+---------+
| 2 | 2 | 2 | extra 2 |
| 3 | 3 | 3 | extra 3 |
| 4 | 5 | NULL | NULL |
| 6 | 6 | 66 | NULL |
+----+---+------+---------+
4 rows in set (0.00 sec)
mysql> replace into auto(id,k,v)values(6,2,88);
Query OK, 3 rows affected (0.03 sec)
像上面的,主鍵id=6對應一條記錄,唯一索引k=2對應id=2的另外一條記錄,所以我們當前插入的記錄就會跟2行資料有衝突,我們replace into 看看會有什麼結果
mysql> replace into auto(id,k,v)values(6,2,88);
Query OK, 3 rows affected (0.03 sec)
mysql> select * from auto;
+----+---+------+---------+
| id | k | v | extra |
+----+---+------+---------+
| 3 | 3 | 3 | extra 3 |
| 4 | 5 | NULL | NULL |
| 6 | 2 | 88 | NULL |
+----+---+------+---------+
3 rows in set (0.00 sec)
mysql> show create table auto \G
*************************** 1. row ***************************
Table: auto
Create Table: CREATE TABLE `auto` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL,
`v` varchar(100) DEFAULT NULL,
`extra` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
我們發現auto_increment並沒有+1,MySQL把原來的id=6的這條記錄上進行uppdate,但是發現唯一索引k出現了衝突,所以就把對應衝突的那條資料刪除,再進行更新,由於沒有指定更新欄位extra的資料,所以就把extra更新為預設資料
- 如果僅僅是唯一鍵衝突呢?
mysql> select * from auto;
+----+---+------+---------+
| id | k | v | extra |
+----+---+------+---------+
| 2 | 2 | 2 | extra 2 |
| 3 | 3 | 3 | extra 3 |
| 4 | 5 | NULL | NULL |
| 5 | 6 | NULL | 77 |
+----+---+------+---------+
4 rows in set (0.00 sec)
mysql> show create table auto \G
*************************** 1. row ***************************
Table: auto
Create Table: CREATE TABLE `auto` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL,
`v` varchar(100) DEFAULT NULL,
`extra` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql>
mysql> replace into auto(k,v)values(6,66);
Query OK, 2 rows affected (0.04 sec)
mysql> select * from auto;
+----+---+------+---------+
| id | k | v | extra |
+----+---+------+---------+
| 2 | 2 | 2 | extra 2 |
| 3 | 3 | 3 | extra 3 |
| 4 | 5 | NULL | NULL |
| 6 | 6 | 66 | NULL |
+----+---+------+---------+
4 rows in set (0.00 sec)
mysql> show create table auto \G
*************************** 1. row ***************************
Table: auto
Create Table: CREATE TABLE `auto` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL,
`v` varchar(100) DEFAULT NULL,
`extra` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
這時候,我們發現,,auto_increment已經+1了。MySQL這時候的執行步驟是,首先往表裡面插入一條資料,這時候auto_increment+1,但是在插入的時候發現唯一索引的k衝突了,然後把衝突的這條資料刪除,然後重新插入,對於沒有指定其他列(extra)的值,如extra都使用了預設值變成了null
現在我們可以下結論了:
- 當replace into 記錄只與主鍵衝突的時候,auto_increment不會增加,它會對與主鍵衝突的那一條記錄進行更新,沒有指定的列將會被更新為預設值
- 當replace into 記錄與主鍵跟唯一索引同時衝突的時候,auto_increment不會增加
- 如果衝突的主鍵和索引在同一行記錄,則replace into只做更新,對於沒有指定值的其他列,將會被更新為預設值,
- 如果衝突的主鍵和索引分別對應2行資料,則MySQL將會刪除唯一索引的那一行記錄,更新對應主鍵的那一行記錄。
- 當replace into 記錄只與唯一索引進行衝突的時候,auto_increment + 1,再對資料進行更新。
- 最後我們可以對總結分析下,MySQL對replace into的操作是首先是insert操作,如果insert失敗,則對insert失敗的這條記錄進行update,如果update還是失敗,則會進行delete操作之後再update。
- 具體流程是這樣的:insert記錄,發現主鍵衝突,則update這一行,update的時候發現存在唯一鍵衝突,則delete對應的唯一鍵的行後再進行update。如果insert成功,auto_increment自然+1了,然後對這條記錄進行update,update的時候發現存在唯一鍵衝突,則delete對應的唯一鍵的行後再進行update。