本文主要描述了PolarDB-X中的affected rows行為。
注意事項
PolarDB-X從5.4.17-16921956版本開始對DML在useAffectedRows=true情況下的affected rows進行相容性適配。
PolarDB-X分布式情境下,邏輯DML執行較為複雜,affected rows行為和MySQL略有不同。
JDBC url中useAffectedRows會影響CLIENT_FOUND_ROWS標記位,useAffectedRows預設為false,CLIENT_FOUND_ROWS預設為true,而命令列CLIENT_FOUND_ROWS預設為false。
CLIENT_FOUND_ROWS為true時,DML返回的是匹配的行數,為false時,返回的是更新的行數。
MySQL官方文檔中描述了CLIENT_FOUND_ROWS的影響,隻影響UPDATE和UPSERT。
在使用affected rows作為商務邏輯判斷前,建議進行測試並固化為單元測試用例,後續PolarDB-X新版本的預設行為可能會發生變化。
在使用 MySQL connector JDBC介面訪問PolarDB-X時,是預設使用useAffectedRows=false配置的,即CLIENT_FOUND_ROWS = ON,可以在連結URL中添加useAffectedRows=true來使用修改行數返回。
在使用MySQL client命令列程式時,預設CLIENT_FOUND_ROWS=OFF,即DML預設返回的是修改行數。
已知行為不一致
replace into
只有唯一鍵,沒有主鍵的表,且插入的新老資料完全一樣。
說明該情況行為和MySQL不一樣,但是是預期行為。
PolarDB-X 2.0
CREATE TABLE `replace_test_tb_no_pk_with_uk` ( `id` bigint(11) NOT NULL DEFAULT '1', `c1` bigint(20) DEFAULT NULL, `c2` bigint(20) DEFAULT NULL, `c3` bigint(20) DEFAULT NULL, `c4` bigint(20) DEFAULT NULL, `c5` varchar(255) DEFAULT NULL, `c6` datetime DEFAULT NULL, `c7` text, `c8` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, `_drds_implicit_id_` bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`_drds_implicit_id_`), UNIQUE LOCAL KEY `u_id` (`id`) ) ENGINE = InnoDB AUTO_INCREMENT = 100022 DEFAULT CHARSET = utf8 PARTITION BY KEY(`id`) PARTITIONS 7 /* tablegroup = `tg602` */ delete from replace_test_tb_no_pk_with_uk; Query OK, 2 rows affected (0.09 sec) replace into replace_test_tb_no_pk_with_uk(id, c1, c5, c8) values(1, 1, 'a', '2020-06-16 06:49:32'); Query OK, 1 row affected (0.05 sec) replace into replace_test_tb_no_pk_with_uk(id, c1, c5, c8) values(1, 1, 'a', '2020-06-16 06:49:32'); Query OK, 2 rows affected (0.03 sec) mysql> replace into replace_test_tb_no_pk_with_uk(id, c1, c5, c8) values(1, 1, 'a', '2020-06-16 06:49:32'); Query OK, 2 rows affected (0.11 sec)MySQL
CREATE TABLE `replace_test_tb_no_pk_with_uk` ( `id` bigint(11) NOT NULL DEFAULT '1', `c1` bigint(20) DEFAULT NULL, `c2` bigint(20) DEFAULT NULL, `c3` bigint(20) DEFAULT NULL, `c4` bigint(20) DEFAULT NULL, `c5` varchar(255) DEFAULT NULL, `c6` datetime DEFAULT NULL, `c7` text, `c8` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY `u_id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 delete from replace_test_tb_no_pk_with_uk; Query OK, 2 rows affected (0.00 sec) replace into replace_test_tb_no_pk_with_uk(id, c1, c5, c8) values(1, 1, 'a', '2020-06-16 06:49:32'); Query OK, 1 row affected (0.00 sec) replace into replace_test_tb_no_pk_with_uk(id, c1, c5, c8) values(1, 1, 'a', '2020-06-16 06:49:32'); Query OK, 1 row affected (0.00 sec) replace into replace_test_tb_no_pk_with_uk(id, c1, c5, c8) values(1, 1, 'a', '2020-06-16 06:49:32'); Query OK, 1 row affected (0.00 sec)原因為:無主鍵的表會建立隱式主鍵,基於效能原因,會直接下推replace into,隱式主鍵會自動帶上自增的sequence,導致即使插入的資料完全一致,隱式主鍵也不一致,affected rows為一次delete一次insert,即為2。
本地唯一鍵非拆分鍵,唯一約束範圍僅在當前分區。
說明該情況行為和 MySQL 不一樣,但是是預期行為。
PolarDB-X 2.0
CREATE TABLE `replace_test_tbl` ( `id` int(11) NOT NULL, `a` int(11) DEFAULT '1', `b` int(11) DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `b` (`b`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 PARTITION BY KEY(`id`) PARTITIONS 3 replace into replace_test_tbl (id,a,b) values (0,1,1),(1,2,2),(2,3,3),(100,100,100),(101,103,103); Query OK, 5 rows affected (0.03 sec) replace into replace_test_tbl (id) values (1); Query OK, 2 rows affected (0.01 sec) replace into replace_test_tbl (id,a,b) values (3,0+2,0+2); Query OK, 1 row affected (0.01 sec) select * from replace_test_tbl; +-----+------+------+ | id | a | b | +-----+------+------+ | 1 | 1 | 0 | | 101 | 103 | 103 | | 100 | 100 | 100 | | 0 | 1 | 1 | | 2 | 3 | 3 | | 3 | 2 | 2 | +-----+------+------+ 6 rows in set (0.03 sec) replace into replace_test_tbl (id,a,b) values (1,2,2),(2,3,3); Query OK, 4 rows affected (0.02 sec) mysql> select * from replace_test_tbl; +-----+------+------+ | id | a | b | +-----+------+------+ | 0 | 1 | 1 | | 2 | 3 | 3 | | 3 | 2 | 2 | | 1 | 2 | 2 | | 101 | 103 | 103 | | 100 | 100 | 100 | +-----+------+------+ 6 rows in set (0.04 sec)MySQL
CREATE TABLE `replace_test_tbl` ( `id` int(11) NOT NULL, `a` int(11) DEFAULT '1', `b` int(11) DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `b` (`b`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 replace into replace_test_tbl (id,a,b) values (0,1,1),(1,2,2),(2,3,3),(100,100,100),(101,103,103); Query OK, 5 rows affected (0.00 sec) Records: 5 Duplicates: 0 Warnings: 0 replace into replace_test_tbl (id) values (1); Query OK, 2 rows affected (0.01 sec) replace into replace_test_tbl (id,a,b) values (3,2,2); Query OK, 1 row affected (0.00 sec) select * from replace_test_tbl; +-----+------+------+ | id | a | b | +-----+------+------+ | 0 | 1 | 1 | | 1 | 1 | 0 | | 2 | 3 | 3 | | 3 | 2 | 2 | | 100 | 100 | 100 | | 101 | 103 | 103 | +-----+------+------+ 6 rows in set (0.00 sec) replace into replace_test_tbl (id,a,b) values (1,2,2),(2,3,3); Query OK, 5 rows affected (0.00 sec) Records: 2 Duplicates: 3 Warnings: 0 select * from replace_test_tbl; +-----+------+------+ | id | a | b | +-----+------+------+ | 0 | 1 | 1 | | 1 | 2 | 2 | | 2 | 3 | 3 | | 100 | 100 | 100 | | 101 | 103 | 103 | +-----+------+------+ 5 rows in set (0.00 sec)
insert on duplicate key update
使用DML_SKIP_TRIVIAL_UPDATE=false hint時。
說明該情況行為和MySQL不一樣,但是是預期行為。
/*+TDDL: cmd_extra(DML_SKIP_TRIVIAL_UPDATE=FALSE)*/當包含該hint時,並不會判斷update前後的值是否一致,都會當成不一致進而執行update操作,用於處理等值判斷失誤的情況,affected rows也不再準確。正常情況下不建議使用,僅在工單反饋、值班研發推薦下才可以使用,並需要評估影響。
batch insert中對原資料A->B->C->A認為是沒有更新。
說明相容性缺陷,已於5.4.17-16971811版本修複。
PolarDB-X 2.0
CREATE PARTITION TABLE `tb` ( `id` int(11) NOT NULL, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE GLOBAL INDEX /* ua_$b525 */ `ua` (`a`) PARTITION BY KEY(`a`) PARTITIONS 3, UNIQUE LOCAL KEY `_local_ua` (`a`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 PARTITION BY KEY(`id`) PARTITIONS 3 insert into tb values (1,1,1),(2,2,2),(3,1,3),(4,1,4),(5,1,1) on duplicate key update b=values(b); Query OK, 8 rows affected (0.44 sec) # 錯誤結果 insert into tb values (1,1,1),(2,2,2),(3,1,3),(4,1,4),(5,1,1) on duplicate key update b=values(b); Query OK, 0 rows affected (0.15 sec) # 錯誤結果 insert into tb values (1,1,1),(2,2,2),(3,1,3),(4,1,4),(5,1,1) on duplicate key update b=values(b); Query OK, 0 rows affected (0.16 sec) # 修複後 insert into tb values (1,1,1),(2,2,2),(3,1,3),(4,1,4),(5,1,1) on duplicate key update b=values(b); Query OK, 6 rows affected (0.23 sec)MySQL
CREATE TABLE `tb` ( `id` int(11) NOT NULL, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ua` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 insert into tb values (1,1,1),(2,2,2),(3,1,3),(4,1,4),(5,1,1) on duplicate key update b=values(b); Query OK, 8 rows affected (0.00 sec) Records: 5 Duplicates: 3 Warnings: 0 insert into tb values (1,1,1),(2,2,2),(3,1,3),(4,1,4),(5,1,1) on duplicate key update b=values(b); Query OK, 6 rows affected (0.00 sec) Records: 5 Duplicates: 3 Warnings: 0 insert into tb values (1,1,1),(2,2,2),(3,1,3),(4,1,4),(5,1,1) on duplicate key update b=values(b); Query OK, 6 rows affected (0.00 sec) Records: 5 Duplicates: 3 Warnings: 0
update
reloacte情況下affected rows計算有誤。
相容性缺陷,已於5.4.17-16971811版本修複。
PolarDB-X 2.0
CREATE TABLE `update_relocate_tb` (
`id` int(11) NOT NULL,
`a` varchar(100) DEFAULT NULL,
`b` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4
PARTITION BY KEY(`id`)
PARTITIONS 3
insert into update_relocate_tb (id,a)values (1, 'fdas');
Query OK, 1 row affected (0.11 sec)
update update_relocate_tb set id=1,a=0 where id=1;
Query OK, 1 row affected (0.08 sec)
# 錯誤結果
update update_relocate_tb set id=1,a=0 where id=1;
Query OK, 1 rows affected (0.11 sec)
# 修複後
update update_relocate_tb set id=1,a=0 where id=1;
Query OK, 0 rows affected (0.11 sec)MySQL
CREATE TABLE `update_relocate_tb` (
`id` int(11) NOT NULL,
`a` varchar(100) DEFAULT NULL,
`b` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into update_relocate_tb (id,a)values (1, 'fdas');
Query OK, 1 row affected (0.00 sec)
update update_relocate_tb set id=1,a=0 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
update update_relocate_tb set id=1,a=0 where id=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0JSON
該情況行為和MySQL不一樣。目前PolarDB-X不支援JSON類型列的資料比較,所以關於JSON的資料更新僅通過字串對比判斷,affected rows結果可能並不準確。