1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
REPLACE
[LOW_PRIORITY | DELAYED]
[
INTO
] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
{
VALUES
| VALUE} ({expr |
DEFAULT
},...),(...),...
Or
:
REPLACE
[LOW_PRIORITY | DELAYED]
[
INTO
] tbl_name
[PARTITION (partition_name,...)]
SET
col_name={expr |
DEFAULT
}, ...
Or
:
REPLACE
[LOW_PRIORITY | DELAYED]
[
INTO
] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
SELECT
...
|
replace的工做机制有点像insert,只不过若是在表里若是一行有PRIMARY KEY或者UNIQUE索引,那么就会把老行删除而后插入新行。如:mysql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
root@test 03:23:55>show
create
table
lingluo\G
*************************** 1. row ***************************
Table
: lingluo
Create
Table
:
CREATE
TABLE
`lingluo` (
`a`
int
(11)
NOT
NULL
DEFAULT
'0'
,
`b`
int
(11)
DEFAULT
NULL
,
`c`
int
(11)
DEFAULT
NULL
,
`d`
int
(11)
DEFAULT
NULL
,
PRIMARY
KEY
(`a`),
--------------------------同时存在PK约束
UNIQUE
KEY
`uk_bc` (`b`,`c`)
----------------惟一索引约束
) ENGINE=InnoDB
DEFAULT
CHARSET=gbk
1 row
in
set
(0.01 sec)
root@test 02:01:44>
select
*
from
lingluo;
Empty
set
(0.00 sec)
root@test 03:27:40>
replace
into
lingluo
values
(1,10000,3,4);
--------表里没有已存在的记录至关于insert
Query OK, 1 row affected (0.00 sec)
-----------------------affect_rows是1
binlog格式:
|
1
2
3
|
root@test 02:11:18>
replace
into
lingluo
values
(1,10000,3,5);
-------已经存在记录,且PK和UK同时冲突的时候,至关于先delete再insert
Query OK, 2
rows
affected (0.00 sec)
----------------------affect_rows是2,是delete和insert行数的总和
binlog格式:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
root@test 02:26:09>
select
*
from
lingluo;
+
---+-------+------+------+
| a | b | c | d |
+
---+-------+------+------+
| 1 | 10000 | 3 | 5 |
+
---+-------+------+------+
1 row
in
set
(0.00 sec)
root@test 02:31:54>
replace
into
lingluo
values
(1,10000,4,5);
-------已经存在记录,且PK同时冲突的时候,至关于先delete再insert
Query OK, 2
rows
affected (0.00 sec)
---------------------------------affect_rows是2,是delete和insert行数的总和
root@test 02:32:02>
select
*
from
lingluo;
+
---+-------+------+------+
| a | b | c | d |
+
---+-------+------+------+
| 1 | 10000 | 4 | 5 |
+
---+-------+------+------+
binlog格式:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
root@test 02:37:04>
replace
into
lingluo
values
(4,10000,6,5);
Query OK, 1 row affected (0.00 sec)
root@test 02:37:59>
replace
into
lingluo
values
(6,10000,6,5);
-------已经存在记录,且UK同时冲突的时候,直接update
Query OK, 2
rows
affected (0.00 sec)
---------------------------------affect_rows是2
root@test 02:40:31>
select
*
from
lingluo;
+
---+-------+------+------+
| a | b | c | d |
+
---+-------+------+------+
| 1 | 10000 | 4 | 5 |
| 3 | 10000 | 5 | 5 |
| 6 | 10000 | 6 | 5 |
+
---+-------+------+------+
3
rows
in
set
(0.00 sec)
binlog格式:
|
疑问:算法
既然uk冲突的时候是update,那么为何affect_rows都是2呢?让咱们从源码上分析看下:sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
指定列
replace
:
root@test 03:34:37>
select
*
from
u;
+
----+------+------+
| id | age | d |
+
----+------+------+
| 0 | 1 | 126 |
| 1 | 0 | 1 |
| 3 | 1 | 123 |
| 4 | 1 | 127 |
| 5 | 0 | 12 |
| 7 | 2 | 129 |
+
----+------+------+
6
rows
in
set
(0.00 sec)
root@test 03:34:37>
select
*
from
u;
+
----+------+------+
| id | age | d |
+
----+------+------+
| 0 | 1 | 126 |
| 1 | 0 | 1 |
| 3 | 1 | 123 |
| 4 | 1 | 127 |
| 5 | 0 | 12 |
| 7 | 2 | 129 |
+
----+------+------+
6
rows
in
set
(0.00 sec)
root@test 03:34:40>
replace
into
u (age,d)
values
(0,130);
Query OK, 2
rows
affected, 1 warning (0.01 sec)
root@test 03:40:39>show warnings;
+
---------+------+-----------------------------------------+
|
Level
| Code | Message |
+
---------+------+-----------------------------------------+
| Warning | 1364 | Field
'id'
doesn't have a
default
value |
+
---------+------+-----------------------------------------+
1 row
in
set
(0.00 sec)
root@test 03:40:47>
select
*
from
u;
+
----+------+------+
| id | age | d |
+
----+------+------+
| 0 | 0 | 130 |
-----------------由于id是parimary可是没有auto_creasement,由126变成130
| 1 | 0 | 1 |
| 3 | 1 | 123 |
| 4 | 1 | 127 |
| 5 | 0 | 12 |
| 7 | 2 | 129 |
+
----+------+------+
6
rows
in
set
(0.00 sec)
|
用的时候须要注意的是:安全
若是指定replace列的话,尽可能写全,要否则没有输入值的列数据会被赋成默认值(由于是先delete在insert),就和普通的insert是同样的,因此若是你要执行replace语句的话是须要insert和delete权限的。spa
若是你须要执行 SET
,就至关于执行col_name
= col_name
+ 1
.日志col_name
= DEFAULT(col_name
) + 1
replace语句若是不深刻看的话,就和insert同样,执行完后没什么反应code
例:索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
root@test 04:20:04>
select
*
from
u;
+
----+------+------+
| id | age | d |
+
----+------+------+
| 0 | 0 | 130 |
| 1 | 0 | 1 |
| 3 | 1 | 123 |
| 4 | 1 | 127 |
| 5 | 0 | 12 |
| 7 | 2 | 129 |
+
----+------+------+
6
rows
in
set
(0.00 sec)
root@test 04:20:10>
replace
into
u (id,d)
values
(8,232);
Query OK, 1 row affected (0.01 sec)
root@test 04:20:39>
select
*
from
u;
+
----+------+------+
| id | age | d |
+
----+------+------+
| 0 | 0 | 130 |
| 1 | 0 | 1 |
| 3 | 1 | 123 |
| 4 | 1 | 127 |
| 5 | 0 | 12 |
| 7 | 2 | 129 |
| 8 |
NULL
| 232 |
+
----+------+------+
7
rows
in
set
(0.00 sec)
root@test 04:20:43>
replace
into
u (id,d)
values
(7,232);
Query OK, 3
rows
affected (0.01 sec)
----------注意这里affect_rows是3,由于主键7已经存在,惟一索引232已经存在,因此须要删除id为7和8的行,而后插入新行
root@test 04:20:52>
select
*
from
u;
+
----+------+------+
| id | age | d |
+
----+------+------+
| 0 | 0 | 130 |
| 1 | 0 | 1 |
| 3 | 1 | 123 |
| 4 | 1 | 127 |
| 5 | 0 | 12 |
| 7 |
NULL
| 232 |
+
----+------+------+
6
rows
in
set
(0.00 sec)
root@test 04:20:55>
|
MySQL给replace和load data....replace用的算法是:ci
尝试向表里插入新行源码
当表里惟一索引或者primary key冲突的时候:
a. delete冲突行
b.往表里再次插入新行
若是遇到重复行冲突,存储过程极可能看成update执行,而不是delete+insert,可是显式上都是同样的。这里没有用户可见的影响除了存储引擎层Handler_xxx
的状态变量。
由于REPLACE ... SELECT语句的结果依赖于select的行的顺序,可是顺序没办法保证都是同样的,有可能从master和slave的都不同。正是基于这个缘由,MySQL 5.6.4之后,REPLACE ... SELECT语句被标记为基于statement的复制模式不安全的。基于这个变化,当使用STATEMENT记录二进制日志的时候,若是有这样的语句就会在log里面输出一个告警,一样当使用MIXED行复制模式也会记录告警。
在MySQL5.6.6以前的版本,replace影响分区表就像MyISAM使用表级锁锁住全部的分区表同样。当使用 REPLACE ... PARTITION
语句时确实会发生上述状况。(使用基于行锁的InnoDB引发不会发生这种状况。)在MySQL 5.6.6之后的版本MySQL使用分区锁,只有当分区(只要没有分区表的列更新)包含了REPLACE语句而且WHERE实际匹配到的才会锁住那个分区;不然的话就会锁住整个表。
操做形式:
binlog格式:
当存在pk冲突的时候是先delete再insert
当存在uk冲突的时候是直接update