ALTER TABLE orders ADD INDEX idx_uid (user_id),
ALGORITHM=INPLACE, LOCK=NONE;
SELECT * FROM information_schema.innodb_trx
WHERE time > 60;

在 600 万行的订单表上执行 ALTER TABLE ADD INDEX,业务写入停了 18 分钟,监控里 insert 全部堆积,应用侧 connection timeout 一路涨。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,普通建索引要拿元数据锁,前面还排着一个没提交的长事务时,DDL 只能等,后面所有写请求又排在 DDL 后面。版本支持 online DDL 也不代表一定不锁,语句退化成拷贝表就全程锁写。

「加索引锁表」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。改完隔一天再看一次,当场正常不代表能稳住。

测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。

处理上按这个顺序:先查当前有没有长事务 有就先处理再动 DDL;用 ALGORITHM=INPLACE, LOCK=NONE 显式声明 不支持就报错而不是默默锁表;千万级表改用 gh-ost 在备表上建;挑低峰执行 并把 DDL 超时时间设短。

改完只确认一件事:DDL 执行期间写入正常 QPS 不掉 索引建完后 explain 能命中。

作者 9823189