REPLACE与INSERT INTO ... ON DUPLICATE KEY总结

INSERT … ON DUPLICATE KEY UPDATE 总结

  • 当主键或唯一键冲突时,执行更新操作,否则执行插入操作,auto_increment始终累加。
  • 更新操作受多个唯一键影响,在MySQL5.6.6之后的SBR中被标记为不安全的
  • UPDATE子句可使用VALUES(col_name)使用Insert语句中列的值
  • DELAYED选项将被忽略
  • MySQL5.6.6之前,对于表级锁存储引擎(MyISAM),该语句会锁定分区表中所有分区。MySQL5.6.6之后,只会锁定所更新的分区(InnoDB无影响)
  • INSERT … SELECT ON DUPLICATE KEY UPDATE可能导致主从数据不一致,因此该语句在MySQL5.6.4之后的SBR中被标记为不安全的。
  • 当没有主键或唯一键冲突时,与replace相同相当于普通的insert.
mysql> create table test(a int primary key auto_increment,b varchar(10),c varchar(10),d int);
Query OK, 0 rows affected (0.03 sec)

mysql> alter table test add unique index uq_b(b);
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into test (a,b,c,d) values(1,'1','1',1) on duplicate key update c='2', d=2;
Query OK, 1 row affected (0.02 sec)

mysql> select * from test;
+---+------+------+------+
| a | b    | c    | d    |
+---+------+------+------+
| 1 | 1    | 2    |    1 |
+---+------+------+------+
1 row in set (0.01 sec)

mysql> insert into test (a,b,c,d) values(2,'1','1',1) on duplicate key update d=2;
Query OK, 2 rows affected (0.00 sec)

mysql> select * from test;
+---+------+------+------+
| a | b    | c    | d    |
+---+------+------+------+
| 1 | 1    | 2    |    2 |
+---+------+------+------+
1 row in set (0.00 sec)

mysql> insert into test (a,b,c,d) values(null,'2','2',1) on duplicate key update d= values(a);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test;
+---+------+------+------+
| a | b    | c    | d    |
+---+------+------+------+
| 1 | 1    | 2    |    2 |
| 2 | 2    | 2    |    1 |
+---+------+------+------+
2 rows in set (0.01 sec)

mysql> insert into test (a,b,c,d) values(null,'2','2',1) on duplicate key update d= values(a);
Query OK, 2 rows affected (0.01 sec)

mysql> select * from test;
+---+------+------+------+
| a | b    | c    | d    |
+---+------+------+------+
| 1 | 1    | 2    |    2 |
| 2 | 2    | 2    |    3 |
+---+------+------+------+
2 rows in set (0.00 sec)

mysql> insert into test (a,b,c,d) values(null,'2','2',1) on duplicate key update d= values(a);
Query OK, 2 rows affected (0.01 sec)

mysql> select * from test;
+---+------+------+------+
| a | b    | c    | d    |
+---+------+------+------+
| 1 | 1    | 2    |    2 |
| 2 | 2    | 2    |    4 |
+---+------+------+------+
2 rows in set (0.00 sec)

mysql> insert into test (a,b,c,d) values(null,'3','3',3);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test;
+---+------+------+------+
| a | b    | c    | d    |
+---+------+------+------+
| 1 | 1    | 2    |    2 |
| 2 | 2    | 2    |    4 |
| 5 | 3    | 3    |    3 |
+---+------+------+------+
3 rows in set (0.01 sec)

REPLACE总结

  • 当主键或唯一键冲突时,执行删除操作,然后执行插入操作,否则直接执行插入操作。
  • 使用REPLACE时,必须同时拥有INSERT及DELETE权限
  • MySQL 5.6.2之后,REPLACE可使用PARTITION选项指明明确的分区或子分区
  • REPLACE不能使用冲突列的值,如不指定列值将被设置为默认值
  • 删除操作受多个唯一键影响,受影响的行数是删除和插入的行的总和
  • REPLACE表不支持子查询中查询同一个表
  • REPLACE … SELECT可能导致主从数据不一致,因此该语句在MySQL5.6.4之后的SBR中被标记为不安全的。
  • MySQL5.6.6之前,对于表级锁存储引擎(MyISAM),该语句会锁定分区表中所有分区,即使使用REPLACE … PARTITION语句。MySQL5.6.6之后,如不更新分区列,只锁定与WHERE子句匹配的分区,如更新分区列,整个表将被锁定

REPLACE算法(LOAD DATA… REPLACE):

  1. 尝试向表中插入新记录
  2. 因为主键或唯一索引中的重复键错误导致插入失败
  3. 从表中删除与重复键值冲突的记录
  4. 再次向表中插入新记录
mysql> select * from test;
+----+------+------+------+
| a  | b    | c    | d    |
+----+------+------+------+
|  1 | 1    | 2    |    2 |
|  2 | 2    | 2    |    2 |
|  4 | 4    | 4    |    4 |
|  5 | 3    | 3    |    7 |
|  8 | 12   | 8    |    8 |
| 13 | 14   | 10   |   14 |
| 14 | 10   | 10   |   10 |
+----+------+------+------+
7 rows in set (0.01 sec)

mysql> replace into test (a,b,c,d) values (14,'14',9,9);
Query OK, 3 rows affected (0.01 sec)

mysql> select * from test;
+----+------+------+------+
| a  | b    | c    | d    |
+----+------+------+------+
|  1 | 1    | 2    |    2 |
|  2 | 2    | 2    |    2 |
|  4 | 4    | 4    |    4 |
|  5 | 3    | 3    |    7 |
|  8 | 12   | 8    |    8 |
| 14 | 14   | 9    |    9 |
+----+------+------+------+
6 rows in set (0.00 sec)

mysql> replace into test (a,b,c,d) values (14,NULL,'',14);
Query OK, 2 rows affected (0.01 sec)

mysql> select * from test;
+----+------+------+------+
| a  | b    | c    | d    |
+----+------+------+------+
|  1 | 1    | 2    |    2 |
|  2 | 2    | 2    |    2 |
|  4 | 4    | 4    |    4 |
|  5 | 3    | 3    |    7 |
|  8 | 12   | 8    |    8 |
| 14 | NULL |      |   14 |
+----+------+------+------+
6 rows in set (0.00 sec)


mysql> REPLACE INTO test SET a = 14 ,b= (select b from test where b = 12) ,c='12',d=12;
ERROR 1093 (HY000): You can't specify target table 'test' for update in FROM clause
mysql> select b from test where b = 12;
+------+
| b    |
+------+
| 12   |
+------+
1 row in set (0.02 sec)

mysql> REPLACE INTO test SET a = 14 ,b= (select '12') ,c='12',d=12;
Query OK, 3 rows affected (0.01 sec)

mysql> select * from test;
+----+------+------+------+
| a  | b    | c    | d    |
+----+------+------+------+
|  1 | 1    | 2    |    2 |
|  2 | 2    | 2    |    2 |
|  4 | 4    | 4    |    4 |
|  5 | 3    | 3    |    7 |
| 14 | 12   | 12   |   12 |
+----+------+------+------+
5 rows in set (0.00 sec)

整理自网络

Svoid
2015-01-09
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章