RDS MySQL对DDL执行过程中唯一键冲突问题进行了优化,有效减少了该问题导致的DDL失败,提升了DDL的成功率。
背景:MySQL的Online 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.4 MySQL 8.0且内核小版本大于等于20250531 使用DDL唯一键冲突优化功能时,有以下限制条件: 不支持主键发生变化的DDL。 不支持处理DDL执行过程中新增的唯一索引上发生的冲突。 不支持包含虚拟列的唯一索引和多值唯一索引。 您可以通过设置参数 参数名称 说明 描述:开启或关闭DDL唯一键冲突优化。 参数范围:全局参数。 数据类型: 默认值: 取值范围: 是否需要重启实例:否。 访问RDS实例列表,在上方选择地域,然后单击目标实例ID。 在左侧导航栏中单击参数设置。 在可修改参数页签内搜索待修改参数,并配置参数值。 单击确定,然后单击提交参数,并在弹出的窗口中选择生效的时间段。 您可以通过以下步骤,测试开启与关闭DDL唯一键冲突优化功能时DDL的执行情况: 构建包含唯一键的数据表并插入数据。 启动一个会话并持续插入重复值,触发唯一键冲突。 启动另一个会话,分别测试开启与关闭DDL唯一键冲突优化功能时DDL的执行情况。 不开启DDL唯一键冲突优化功能,DDL执行失败并报错。 开启DDL唯一键冲突优化功能后,DDL执行成功。 功能说明
适用范围
参数管理
参数说明
innodb_online_alter_ignore_dup_key_error_for_uk来开关DDL唯一键冲突优化功能。innodb_online_alter_ignore_dup_key_error_for_ukBoolean。ON。ON或OFF。修改参数
功能效果
测试方法
-- 创建带有唯一键的表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);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);ALTER TABLE test_db.unique_test ENGINE = InnoDB;
测试结果
-- innodb_online_alter_ignore_dup_key_error_for_uk = OFFmysql> ALTER TABLE test_db.unique_test ENGINE = InnoDB;
ERROR 1062 (23000): Duplicate entry 'user_1' for key 'unique_test.uk_user_id'
-- innodb_online_alter_ignore_dup_key_error_for_uk = ONmysql> ALTER TABLE test_db.unique_test ENGINE = InnoDB;
Query OK, 0 rows affected (6.03 sec)
Records: 0 Duplicates: 0 Warnings: 0