MySQL RDS添加Username唯一约束耗时过长求解决方案
问题描述
近期接手某厂商项目,其user表DDL如下:
CREATE TABLE `user` ( `User_ID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `Username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `Password` char(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `Employee_ID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `Role_ID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `Last_Login` datetime DEFAULT NULL, `T_C` int DEFAULT '0', `Locale_ID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `Warehouse_ID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `Client_ID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `Status` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `Creation_Date` datetime DEFAULT NULL, `Created_By` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `Update_Date` datetime DEFAULT NULL, `Updated_By` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `Sub_Client_ID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, PRIMARY KEY (`User_ID`), KEY `Employee_ID` (`Employee_ID`), KEY `Role_ID` (`Role_ID`), KEY `user_ibfk_4_idx` (`Locale_ID`) /*!80000 INVISIBLE */, KEY `user_ibfk_4_idx1` (`Warehouse_ID`), KEY `user_ibfk_3_idx` (`Client_ID`), KEY `user_ibfk_5_idx` (`Sub_Client_ID`), CONSTRAINT `user_ibfk_1` FOREIGN KEY (`Employee_ID`) REFERENCES `employee` (`Employee_ID`), CONSTRAINT `user_ibfk_2` FOREIGN KEY (`Role_ID`) REFERENCES `access_list` (`Role_ID`), CONSTRAINT `user_ibfk_4` FOREIGN KEY (`Locale_ID`) REFERENCES `locale` (`Locale_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
该表仅包含不到10条记录,执行以下语句为Username字段添加唯一约束时,长时间无法完成:
ALTER TABLE user ADD CONSTRAINT Username UNIQUE (Username)
当前使用RDS MySQL 8.0.33版本,尝试设置FOREIGN_KEY_CHECKS=0和FOREIGN_KEY_CHECKS=1均未解决问题。
解决方案
先查锁和事务阻塞
直接查询当前InnoDB锁状态和进程列表,排查是否有未提交事务或锁占用:SHOW ENGINE INNODB STATUS; SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND != 'Sleep';若发现阻塞会话,确认业务无影响后终止:
KILL [会话ID];显式指定ALTER算法
MySQL 8.0添加唯一约束默认使用INPLACE算法,但可能因配置隐式切换到COPY模式,显式指定算法和锁级别试试:ALTER TABLE user ADD CONSTRAINT Username UNIQUE (Username), ALGORITHM=INPLACE, LOCK=NONE;若
LOCK=NONE不支持,可降级为LOCK=SHARED,避免完全锁表。检查RDS实例资源状态
登录RDS控制台查看监控面板,确认CPU、内存、磁盘IO是否出现异常峰值。若存在资源瓶颈,可等待负载降低后重试,或临时升级实例规格。排查重复数据或隐式索引
先检查是否存在重复的Username(可能包含空格、大小写差异等隐性重复):SELECT Username, COUNT(*) FROM user GROUP BY Username HAVING COUNT(*) > 1;再查看是否已存在针对
Username的普通索引:SHOW INDEX FROM user;若有重复数据先清理,若有普通索引先删除,再添加唯一约束。
迁表绕过直接修改
若以上方法均无效,可通过新建表迁移数据的方式实现:- 创建带唯一约束的新表:
CREATE TABLE user_new LIKE user; ALTER TABLE user_new ADD CONSTRAINT Username UNIQUE (Username); - 迁移数据:
INSERT INTO user_new SELECT * FROM user; - 替换原表:
RENAME TABLE user TO user_old, user_new TO user;
操作前务必备份数据,防止数据丢失。
- 创建带唯一约束的新表:
内容的提问来源于stack exchange,提问作者502_Geek
相关产品推荐
相关产品推荐

