全部產品
Search
文件中心

PolarDB:Affected rows行為

更新時間:Jul 06, 2024

本文主要描述了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: 0

JSON

該情況行為和MySQL不一樣。目前PolarDB-X不支援JSON類型列的資料比較,所以關於JSON的資料更新僅通過字串對比判斷,affected rows結果可能並不準確。