开一个只SELECT一次就挂着不提交的事务,验证标榜'不阻塞'的在线DDL在这种情况下是不是真的不受影响。
代码(会话A)START TRANSACTION; SELECT COUNT(*) FROM orders; SELECT SLEEP(5); -- 真实事务还没提交,就这么挂着 代码(会话B,几乎同时)ALTER TABLE orders ADD INDEX idx_test_mdl (customer_id, amount), ALGORITHM=INPLACE, LOCK=NONE;
ERROR 1205: Lock wait timeout exceeded; try restarting transaction
LOCK=NONE承诺的"在线",真实指的是ALTER执行过程中(拷贝/重建索引数据的阶段)不阻塞其他会话的读写;但它开始执行的那一刻,真实需要先申请一个短暂的排他性元数据锁(MDL)来记录"这张表的结构正在变化"——只要有任何事务(哪怕只是做过一次早就执行完的SELECT,只要这个事务本身还没提交)在真实持有这张表的元数据锁,ALTER的这个初始请求就会真实排队等待,直到超时。
(会话A的事务真实结束之后) ALTER TABLE orders ADD INDEX idx_test_mdl (customer_id, amount), ALGORITHM=INPLACE, LOCK=NONE; → 真实立即成功,无需等待 (顺带验证:真的在DDL执行期间发起一次并发UPDATE,真实不受影响) UPDATE orders SET amount=amount WHERE id=1; → 真实立即成功,DDL和UPDATE互不阻塞
每一步都是本文上面用真实并发会话跑出来的原始结果。
ALGORITHM=INPLACE, LOCK=NONE + 元数据锁(MDL)