You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
    

    若有重复数据先清理,若有普通索引先删除,再添加唯一约束。

  • 迁表绕过直接修改
    若以上方法均无效,可通过新建表迁移数据的方式实现:

    1. 创建带唯一约束的新表:
      CREATE TABLE user_new LIKE user;
      ALTER TABLE user_new ADD CONSTRAINT Username UNIQUE (Username);
      
    2. 迁移数据:
      INSERT INTO user_new SELECT * FROM user;
      
    3. 替换原表:
      RENAME TABLE user TO user_old, user_new TO user;
      

    操作前务必备份数据,防止数据丢失。

内容的提问来源于stack exchange,提问作者502_Geek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 10:08:12