DDL唯一键冲突优化

RDS MySQLDDL执行过程中唯一键冲突问题进行了优化,有效减少了该问题导致的DDL失败,提升了DDL的成功率。

功能说明

背景:MySQLOnline DDL允许在DDL期间对目标表进行写入、更新和删除,并将表的修改操作记录到row log中。在DDL执行完成前,系统会应用DDL期间产生的row log,将增量数据补全到新的数据文件中。如果执行DDL的数据表中存在唯一索引,且在DDL执行期间的修改操作中出现了唯一键冲突,row log应用阶段就会出错,导致整个DDL执行失败。由于row log的应用发生在DDL执行完成前,因此该问题导致的DDL失败的代价很大。

简介:RDS MySQL针对此问题进行了优化,Online DDL执行过程中发生唯一键冲突时将不会导致DDL失败,整个DDL可以顺利完成。

适用范围

  • 如需开启DDL唯一键冲突优化功能,数据库大版本须为MySQL 8.0且内核小版本大于等于20250531。当版本不符合要求时,可以升级数据库大版本内核小版本

  • 使用DDL唯一键冲突优化功能时,有以下限制条件:

    • 不支持主键发生变化的DDL。

    • 不支持处理DDL执行过程中新增的唯一索引上发生的冲突。

    • 不支持包含虚拟列的唯一索引和多值唯一索引。

参数管理

参数说明

您可以通过设置参数innodb_online_alter_ignore_dup_key_error_for_uk来开关DDL唯一键冲突优化功能。

参数名称

说明

innodb_online_alter_ignore_dup_key_error_for_uk

  • 描述:开启或关闭DDL唯一键冲突优化。

  • 参数范围:全局参数。

  • 数据类型:Boolean

  • 默认值:ON

  • 取值范围:ONOFF

  • 是否需要重启实例:否。

修改参数

  1. 访问RDS实例列表,在上方选择地域,然后单击目标实例ID。

  2. 在左侧导航栏中单击参数设置

  3. 可修改参数页签内搜索待修改参数,并配置参数值。

  4. 单击确定,然后单击提交参数,并在弹出的窗口中选择生效的时间段。

功能效果

测试方法

您可以通过以下步骤,测试开启与关闭DDL唯一键冲突优化功能时DDL的执行情况:

  1. 构建包含唯一键的数据表并插入数据。

    -- 创建带有唯一键的表
    CREATE DATABASE IF NOT EXISTS test_db;
    USE test_db;
    DROP TABLE IF EXISTS unique_test;
    CREATE TABLE unique_test (
        id         INT AUTO_INCREMENT PRIMARY KEY,
        user_id    VARCHAR(50) NOT NULL,
        name       VARCHAR(100),
        UNIQUE KEY uk_user_id (user_id)
    );
    
    -- 插入初始数据(例如 2,000,000 条)
    DELIMITER $$
    DROP PROCEDURE IF EXISTS insert_initial_data $$
    CREATE PROCEDURE insert_initial_data(IN num_rows INT)
    BEGIN
        DECLARE i INT DEFAULT 1;
        START TRANSACTION;
        WHILE i <= num_rows DO
            SET @uid = CONCAT('user_', i);
            SET @name = CONCAT('Name_', i);
            INSERT INTO unique_test (user_id, name) VALUES (@uid, @name);
            SET i = i + 1;
        END WHILE;
        COMMIT;
    END $$
    DELIMITER ;
    
    CALL insert_initial_data(2000000);
  2. 启动一个会话并持续插入重复值,触发唯一键冲突。

    USE test_db;
    
    DELIMITER $$
    DROP PROCEDURE IF EXISTS insert_duplicate_loop $$
    CREATE PROCEDURE insert_duplicate_loop(
        IN loop_count INT
    )
    BEGIN
        DECLARE i INT DEFAULT 0;
        DECLARE CONTINUE HANDLER FOR 1062 BEGIN END; -- 忽略重复键错误
    
        WHILE i < loop_count DO
            -- 尝试插入已存在的 user_id,触发唯一键冲突
            INSERT INTO unique_test (user_id, name) VALUES ('user_1', 'ConflictUser');
            SET i = i + 1;
        END WHILE;
    END $$
    DELIMITER ;
    
     -- 循环 100000 次重复插入
    CALL insert_duplicate_loop(100000);
  3. 启动另一个会话,分别测试开启与关闭DDL唯一键冲突优化功能时DDL的执行情况。

    ALTER TABLE test_db.unique_test ENGINE = InnoDB;

测试结果

  • 不开启DDL唯一键冲突优化功能,DDL执行失败并报错。

    -- innodb_online_alter_ignore_dup_key_error_for_uk = OFF
    mysql> ALTER TABLE test_db.unique_test ENGINE = InnoDB;
    ERROR 1062 (23000): Duplicate entry 'user_1' for key 'unique_test.uk_user_id'
  • 开启DDL唯一键冲突优化功能后,DDL执行成功。

    -- innodb_online_alter_ignore_dup_key_error_for_uk = ON
    mysql> ALTER TABLE test_db.unique_test ENGINE = InnoDB;
    Query OK, 0 rows affected (6.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0