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