我有一堆连接在一个事务中执行 SELECT,一个执行 DDL。 mysql 手册非常清楚如何在事务中获取元数据锁:
To ensure transaction serializability, the server must not permit one session to perform a data definition language (DDL) statement on a table that is used in an uncompleted explicitly or implicitly started transaction in another session. The server achieves this by acquiring metadata locks on tables used within a transaction and deferring release of those locks until the transaction ends. A metadata lock on a table prevents changes to the table's structure. This locking approach has the implication that a table that is being used by a transaction within one session cannot be used in DDL statements by other sessions until the transaction ends.
这是有道理的,我做了这个测试:
connectionA$ begin;
connectionA$ select * from facebook_authorizations;
connectionA$ ....
connectionB$ alter table facebook_authorizations add column foo int default null;
connectionC$ begin;
connectionC$ select * from facebook_authorizations;
connectionA$ commit;
在我的系统上,当 connectionA 提交时,connectionC 执行并且 connectionB 仍然挂起:它因基于 SELECT 的事务而无法执行。我期待元数据锁定等待列表大致按 FIFO 顺序处理,但似乎并非如此。
是否有关于处理元数据等待队列的顺序的文档?
最佳答案
关于场景的细节:
试图重现这个案例,我阻塞了 session B,然后阻塞了 session C ... 请注意,如果 session B 实际上在获取表上的元数据锁之前正在等待其他内容,则 session C 没有理由等待。
现在,一般来说:
已授予的元数据锁在 performance_schema
表 metadata_locks
中可见,LOCK_STATUS
为 GRANTED
.
查看文档: https://dev.mysql.com/doc/refman/8.0/en/metadata-locks-table.html
这有助于查看哪个 session 拥有哪个锁。
session 正在等待的元数据锁在同一个表中也是可见的,LOCK_STATUS
为 PENDING
。
这有助于了解 session 正在等待什么。
一个(阻塞的) session 等待某个东西的锁定,这反过来可能已经被其他 session 锁定(使用各种 LOCK_TYPE
和 LOCK_DURATION
),但是有这里没有直接的“ session X 等待 session Y”关系,这是由已经存在的锁暗示的。
当几个 session 都在等待同一个资源,并且当资源可用时(一个 session 释放了元数据锁),尝试预测处理顺序(在我看来)是有风险的,应用程序逻辑不应该依赖关于这一点:据我所知,当前的实现确实是一个 FIFO,但这可能会随时更改,并且没有记录在案。
这里的理由是服务器必须有一定的自由度,以便实现不同的调度策略(例如出于性能原因)是可行的。如果某些应用程序以某种方式“期望”给定的顺序,它将中断并阻止任何更改。
关于mysql - 什么是 Mysql 表元数据锁等待队列排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50714253/