TL;DR — 提交事务以解锁 ALTER TABLE。
是的,ALTER TABLE 可以阻塞很长时间。它可能看起来像是永远。它的值实际上是锁等待超时 https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_lock_wait_timeout,默认为 31536000 秒,即 365 天。
在 MySQL 中,像 ALTER TABLE 这样的 DDL 语句需要独占元数据锁 https://dev.mysql.com/doc/refman/8.0/en/metadata-locking.html在桌子上。目的是确保您不会同时从两个并发会话中更改表。
DML 语句(如 SELECT、INSERT、UPDATE、DELETE)也持有“共享”元数据锁。共享锁可以由多个会话同时持有,但会阻塞排它锁,因为排它锁要求它们是唯一一个在表上持有任何类型锁的锁。
文件指出:
这种锁定方法意味着,在事务结束之前,一个会话中的事务正在使用的表不能被其他会话在 DDL 语句中使用。
DML 语句持有元数据锁的目的是这样它们可以保留表的可重复读取视图,而不必担心另一个会话正在执行 DROP TABLE 或 ALTER TABLE 来损害它们的表视图。这种锁定是必要的,因为 MySQL 没有版本化元数据(他们正在逐步朝这个方向努力 https://mysqlserverteam.com/mysql-8-0-data-dictionary-architecture-and-design/).
这意味着运行简单 SELECT 且未提交的事务将阻止需要锁定更改的 DROP TABLE 或 ALTER TABLE。
在线 DDL 的引入存在一些细微差别。
在线DDL性能和并发性 https://dev.mysql.com/doc/refman/8.0/en/innodb-create-index-concurrency.html更详细地描述了 ALTER TABLE 通过获取共享元数据锁开始,因此未提交的事务不会阻塞它。但如果 ALTER TABLE 更改的性质需要,下一阶段可能会将共享元数据锁升级为独占元数据锁。此时,锁获取被阻止,因为另一个事务仍然持有自己的元数据锁。
在线 DDL 并不适用于所有类型的 ALTER TABLE 操作;有些仍然需要独占锁。例如,更改数据类型,就像您所做的那样,需要独占锁。看在线 DDL 概述 https://dev.mysql.com/doc/refman/8.0/en/innodb-create-index-overview.html了解详情。