MySQL的MDL锁
MDL锁的概念和分类
1、MDL类型
锁名称 |
锁类型 |
说明 |
适用语句 |
MDL_INTENTION_EXCLUSIVE |
共享锁 |
意向锁,锁住一个范围 |
任何语句都会获取MDL意向锁, 然后再获取更强级别的MDL锁。 |
MDL_SHARED |
共享锁,表示只访问表结构 |
||
MDL_SHARED_HIGH_PRIO |
共享锁,只访问表结构 |
show create table 等 只访问INFORMATION_SCHEMA的语句 |
|
MDL_SHARED_READ |
访问表结构并且读表数据 |
select语句 LOCK TABLE ... READ |
|
MDL_SHARED_WRITE |
访问表结构并且写表数据 |
SELECT ... FOR UPDATE DML语句 |
|
MDL_SHARED_UPGRADABLE |
可升级锁,访问表结构并且读写表数据 |
Alter语句中间过程会使用 |
|
MDL_SHARED_NO_WRITE |
可升级锁,访问表结构并且读写表数据,并且禁止其它事务写。 |
Alter语句中间过程会使用 |
|
MDL_SHARED_NO_READ_WRITE |
可升级锁,访问表结构并且读写表数据,并且禁止其它事务读写。 |
LOCK TABLES ... WRITE |
|
MDL_EXCLUSIVE |
写锁 |
禁止其它事务读写。 |
CREATE/DROP/RENAME TABLE等DDL语句。 |
2.按对象/范围维度划分
属性 |
含义 |
范围/对象 |
GLOBAL |
全局锁 |
范围 |
COMMIT |
提交保护锁 |
范围 |
SCHEMA |
库锁 |
对象 |
TABLE |
表锁 |
对象 |
FUNCTION |
函数锁 |
对象 |
PROCEDURE |
存储过程锁 |
对象 |
TRIGGER |
触发器锁 |
对象 |
EVENT |
事件锁 |
对象 |
3.按请求/释放锁持续时间划分
属性 |
含义 |
MDL_ STATEMENT |
语句级别 |
MDL_TRANSACTION |
事务级别 |
MDL_EXPLICIT |
需要显示释放 |
4.MDL锁类型的兼容性矩阵
5.MDL Lock实现分类
- scope lock:一般对应全局 MDL Lock,如 flush table with read lock 会获取namespace space:GLOBAL type:S和namespace space:COMMIT type:S的MDL Lock。它包含 GLOBAL, COMMIT, TABLESPACE 和 SCHEMA
- object lock:如其名字所示,对象级别的 MDL Lock,比如 TABLE 级别的 MDL Lock,这也是本文的讨论核心。它包含其他的 namespace。
##源码注释
/**
Helper struct which defines how different types of locks are handled
for a specific MDL_lock. In practice we use only two strategies: "scoped"
lock strategy for locks in GLOBAL, COMMIT, TABLESPACE and SCHEMA namespaces
and "object" lock strategy for all other namespaces.
*/
6.MDL Lock duration(MDL Lock 持续周期)
这个对应源码的 enum_mdl_duration,通常我们需要关注 MDL Lock 是事务提交后释放还是语句结束后释放,实际上就是这个,这对 MDL lock 堵塞的范围很重要。我直接复制源码的解释。
- MDL_STATEMENT:Locks with statement duration are automatically released at the end of statement or transaction.
- MDL_TRANSACTION:Locks with transaction duration are automatically released at the end of transaction.
- MDL_EXPLICIT:Locks with explicit duration survive the end of statement and transaction.They have to be released explicitly by calling MDL_context::release_lock().
7.对于INSERT INTO T SELECT ... FROM S WHERE ...
在RR隔离级别下,会对S表查到的行执行lock next-key;在RC隔离级别下,则不会加锁。
常见 MDL Lock 类型加锁测试
1、MDL_INTENTION_EXCLUSIVE(IX)
这个锁会在很多操作的时候都会出现,比如做任何一个 DML/DDL 操作都会触发,实际上 DELTE/UPDATE/INSERT/FOR UPDATE 等 DML 操作会在 GLOBAL 上加IX锁,然后才会在本对象上加锁。而 DDL 语句至少会在 GLOBAL 上加IX锁,对象所属 SCHEMA 上加IX锁,本对象加锁。
下面是 DELETE 触发的 GLOABL IX MDL LOCK:
2017-08-03T18:22:38.092205Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T18:22:38.092242Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T18:22:38.092276Z3[Note] (--->MDL PRINT) Namespaceis:GLOBAL
2017-08-03T18:22:38.092310Z3[Note] (---->MDL PRINT) Fast path is:(Y)
2017-08-03T18:22:38.092344Z3[Note] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX)
2017-08-03T18:22:38.092380Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_STATEMENT
2017-08-03T18:22:38.092551Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
我们注意一样它的持续周期为语句级别。
下面是 ALETER 语句触发的 GLOABL IX MDL Lock:
2017-08-03T18:46:05.894871Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T18:46:05.894915Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T18:46:05.894948Z3[Note] (--->MDL PRINT) Namespaceis:GLOBAL
2017-08-03T18:46:05.894980Z3[Note] (---->MDL PRINT) Fast path is:(Y)
2017-08-03T18:46:05.895012Z3[Note] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX)
2017-08-03T18:46:05.895044Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_STATEMENT
2017-08-03T18:46:05.895076Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
所以这个 MDL Lock 无所不在,而只有是否兼容问题,如果不兼容则堵塞。scope lock 的 IX 类型一般都是兼容的除非遇到 S 类型,下面讨论。
2、MDL_SHARED(S)
这把锁一般用在 flush tables with read lock 中,如下:
MySQL> flush tables with read lock;
Query OK, 0 rows affected (0.01 sec)
2017-08-03T18:19:11.603911Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T18:19:11.603947Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T18:19:11.603971Z3[Note] (--->MDL PRINT) Namespaceis:GLOBAL
2017-08-03T18:19:11.603994Z3[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED(S)
2017-08-03T18:19:11.604045Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_EXPLICIT
2017-08-03T18:19:11.604073Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
2017-08-03T18:19:11.604133Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T18:19:11.604156Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T18:19:11.604194Z3[Note] (--->MDL PRINT) Namespaceis:COMMIT
2017-08-03T18:19:11.604217Z3[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED(S)
2017-08-03T18:19:11.604240Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_EXPLICIT
2017-08-03T18:19:11.604310Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
我们注意到其 namspace 为 GLOBAL 和 COMMIT 显然他们是 scope lock,他们的 TYPE 为 S,那么很显然根据兼容性原则 scope lock 的 MDL IX 和 MDL S 不兼容,flush tables with read lock 就会堵塞所有 DELTE/UPDATE/INSERT/FOR UPDATE 等 DML 和 DDL 操作,并且也会堵塞 commit 操作。
3、MDL_SHARED_HIGH_PRIO(SH)
这个锁基本上大家也是经常用到只是没感觉到而已,比如我们一般 desc 操作。
兼容矩阵如下:
操作记录如下:
MySQL> desc test.testsort10;
2017-08-03T19:06:05.843277Z4[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T19:06:05.843324Z4[Note] (>MDL PRINT) Thread id is4:
2017-08-03T19:06:05.843359Z4[Note] (->MDL PRINT) DB_name is:test
2017-08-03T19:06:05.843392Z4[Note] (-->MDL PRINT) OBJ_name is:testsort10
2017-08-03T19:06:05.843425Z4[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T19:06:05.843456Z4[Note] (---->MDL PRINT) Fast path is:(Y)
2017-08-03T19:06:05.843506Z4[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_HIGH_PRIO(SH)
2017-08-03T19:06:05.843538Z4[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T19:06:05.843570Z4[Note] (------->MDL PRINT) Mdl status is:EMPTY
这中类型的优先级比较高,但是其和 X 不兼容。注意持续时间为 MDL_TRANSACTION。
4、MDL_SHARED_READ(SR)
这把锁一般用在非当前读取的 select 中。
兼容性如下:
操作记录如下:
MySQL> select* from test.testsort10 limit 1;
2017-08-03T19:13:52.338764Z4[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T19:13:52.338813Z4[Note] (>MDL PRINT) Thread id is4:
2017-08-03T19:13:52.338847Z4[Note] (->MDL PRINT) DB_name is:test
2017-08-03T19:13:52.338883Z4[Note] (-->MDL PRINT) OBJ_name is:testsort10
2017-08-03T19:13:52.338917Z4[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T19:13:52.338950Z4[Note] (---->MDL PRINT) Fast path is:(Y)
2017-08-03T19:13:52.339025Z4[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_READ(SR)
2017-08-03T19:13:52.339062Z4[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T19:13:52.339097Z4[Note] (------->MDL PRINT) Mdl status is:EMPTY
这里还是要提及一下平时我们偶尔会出现 select 也堵住的情况(比如 DDL 的某个阶段需要对象 MDL X 锁)。我们不得不抱怨 MySQL 居然会堵塞 select 其实这里也就是 object mdl lock X 和 SR 不兼容的问题(参考前面的兼容矩阵)。注意持续时间为 MDL_TRANSACTION。
5、MDL_SHARED_WRITE(SW)
这把锁一般用于 DELTE/UPDATE/INSERT/FOR UPDATE 等操作对 table 的加锁(当前读),不包含 DDL 操作,但是要注意 DML 操作实际上还会有一个 GLOBAL 的 IX 的锁,前面已经提及过了,这把锁只是对象上的。
兼容性如下:
操作记录如下:
MySQL> select* from test.testsort10 limit 1for update;
2017-08-03T19:25:41.218428Z4[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T19:25:41.218461Z4[Note] (>MDL PRINT) Thread id is4:
2017-08-03T19:25:41.218493Z4[Note] (->MDL PRINT) DB_name is:test
2017-08-03T19:25:41.218525Z4[Note] (-->MDL PRINT) OBJ_name is:testsort10
2017-08-03T19:25:41.218557Z4[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T19:25:41.218588Z4[Note] (---->MDL PRINT) Fast path is:(Y)
2017-08-03T19:25:41.218620Z4[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_WRITE(SW)
2017-08-03T19:25:41.218677Z4[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T19:25:41.218874Z4[Note] (------->MDL PRINT) Mdl status is:EMPTY
注意持续时间为 MDL_TRANSACTION 。
6、MDL_SHARED_WRITE_LOW_PRIO(SWL)
这把锁很少用到源码注释只有如下:
Usedby DML statements modifying tables andusing the LOW_PRIORITY clause
不做解释了。
7、MDL_SHARED_UPGRADABLE(SU)
这把锁一般在 ALTER TABLE 语句中会用到,他可以升级为 SNW、SNRW、X,同时至少 X 锁也可以降级为 SU,实际上在 Innodb ONLINE DDL 中非常依赖它,由于它的存在那么 DML(SW) 和 SELECT(SR) 都不会堵塞。
兼容性如下:
我们有必要研究一下他的兼容性,可以看到 OBJECT LOCK 中 (SELECT)SR 和 (DML)SW 都是允许的,而在 SCOPED LOCK 中虽然 DML DDL 都会在 GLOBAL 上锁,但是其类型都是 IX。所以这个 SU 锁不堵塞 DML/SELECT 读写操作进入 Innodb 引擎层,它是 ONLINE DDL 的基础。如果不兼容你都进入不了 Innodb 引擎层,更谈不上什么 ONLINE DDL,注意我这里说的 ALGORITHM=INPLACE的ONLINE DDL。
操作日志记录:
MySQL> alter table testsort12 add column it intnotnull;
Query OK, 0 rows affected (6.27 sec)
Records: 0Duplicates: 0Warnings: 0
2017-08-03T19:46:54.781453Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T19:46:54.781487Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T19:46:54.781948Z3[Note] (->MDL PRINT) DB_name is:test
2017-08-03T19:46:54.781990Z3[Note] (-->MDL PRINT) OBJ_name is:testsort12
2017-08-03T19:46:54.782026Z3[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T19:46:54.782060Z3[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_UPGRADABLE(SU)
2017-08-03T19:46:54.782096Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T19:46:54.782175Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
2017-08-03T19:46:54.803898Z3[Note] (upgrade_shared_lock)THIS MDL LOCK will upgrade
2017-08-03T19:46:54.804201Z3[Note] (upgrade_shared_lock)THIS MDL LOCK upgrade TO
2017-08-03T19:46:54.804240Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T19:46:54.804254Z3[Note] (->MDL PRINT) DB_name is:test
2017-08-03T19:46:54.804267Z3[Note] (-->MDL PRINT) OBJ_name is:testsort12
2017-08-03T19:46:54.804280Z3[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T19:46:54.804293Z3[Note] (----->MDL PRINT) Mdl type :MDL_EXCLUSIVE(X)
2017-08-03T19:46:54.804306Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T19:46:54.804319Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
2017-08-03T19:46:54.855563Z3[Note] (downgrade_lock)THIS MDL LOCK will downgrade
2017-08-03T19:46:54.855693Z3[Note] (downgrade_lock) to this MDL lock
2017-08-03T19:46:54.855706Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T19:46:54.855717Z3[Note] (->MDL PRINT) DB_name is:test
2017-08-03T19:46:54.856053Z3[Note] (-->MDL PRINT) OBJ_name is:testsort12
2017-08-03T19:46:54.856069Z3[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T19:46:54.856082Z3[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_UPGRADABLE(SU)
2017-08-03T19:46:54.856094Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T19:46:54.856214Z3[Note] (------->MDL PRIN
我们需要简单分析一下,获得 testsort12 表上的 MDL Lock 大概流程如下:
2017-08-03T19:46:54.781487获得 MDL_SHARED_UPGRADABLE(SU)
2017-08-03T19:46:54.804293升级 MDL_EXCLUSIVE(X) 准备阶段
2017-08-03T19:46:54.855563降级 MDL_SHARED_UPGRADABLE(SU) 执行阶段
2017-08-03T19:47:00.304057升级 MDL_EXCLUSIVE(X) 提交阶段
不管如何这个 ALTER 操作还是比较费时的,从时间我们看到 2017-08-03T19:46:54 降级完成 (SU) 到 2017-08-03T19:47:00 这段时间,实际上是最耗时的实际上这里就是实际的 Inplace 重建,但是这个过程实际在 MDL SU 模式下所以不会堵塞 DML/SELECT 操作。
这里再给大家提个醒,所谓的 ONLINE DDL 只是在 Inplace 重建阶段不堵塞 DML/SELECT 操作,还是尽量在数据库压力小的时候操作,如果有 DML 没有提交或者 SELECT 没有做完这个时候 SW 或者 SR 必然堵塞 X,而 X 为高优先级能够堵塞所有操作。这样导致的现象就是由于 DML 未提交会堵塞 DDL 操作,而 DDL 操作会堵塞所有操作,基本对于这个 TABLE 的表全部操作堵塞(SW 堵塞 X,X 堵塞所有操作)。而对于 ALGORITHM=COPY 在COPY 阶段用的是 SNW 锁,接下来我就先来看看 SNW 锁。
8、MDL_SHARED_NO_WRITE(SNW)
SU 可以升级为 SNW,而 SNW 可以升级为 X,如前面所提及的用于 ALGORITHM=COPY 中,保护数据的一致性。先看看它的兼容性如下:
从兼容矩阵可以看到,本锁不会堵塞 SR,但是堵塞 SW,当然也就堵塞了 DML(SW) 而 SELECT(SR) 不会堵塞。
下面是部分操作记录日志:
MySQL> alter table testsort12 add column ik intnotnull, ALGORITHM=COPY ;
2017-08-03T20:07:58.413215Z3[Note] (upgrade_shared_lock)THIS MDL LOCK upgrade TO
2017-08-03T20:07:58.413241Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T20:07:58.413257Z3[Note] (->MDL PRINT) DB_name is:test
2017-08-03T20:07:58.413273Z3[Note] (-->MDL PRINT) OBJ_name is:testsort12
2017-08-03T20:07:58.413292Z3[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T20:07:58.413308Z3[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_NO_WRITE(SNW)
2017-08-03T20:07:58.413325Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T20:07:58.413341Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
2017-08-03T20:08:25.392006Z3[Note] (upgrade_shared_lock)THIS MDL LOCK upgrade TO
2017-08-03T20:08:25.392024Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T20:08:25.392086Z3[Note] (->MDL PRINT) DB_name is:test
2017-08-03T20:08:25.392159Z3[Note] (-->MDL PRINT) OBJ_name is:testsort12
2017-08-03T20:08:25.392199Z3[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T20:08:25.392214Z3[Note] (----->MDL PRINT) Mdl type is:MDL_EXCLUSIVE(X)
2017-08-03T20:08:25.392228Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T20:08:25.392242Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
我们可以发现如下:
2017-08-03T20:07:58.413308获得了MDL_SHARED_NO_WRITE(SNW)
2017-08-03T20:08:25.392006升级为MDL_EXCLUSIVE(X)
2017-08-03T20:07:58.413308 到 2017-08-03T20:08:25.392006 就是实际 COPY 的时间,可见整个 COPY 期间只能 SELECT,而不能 DML。也是 ALGORITHM=COPY 和 ALGORITHM=INPLACE 的一个关键区别。
9、MDL_SHARED_READ_ONLY(SRO)
用于 LOCK TABLES READ 语句,兼容性如下:
根据兼容性可以发现,堵塞 DML(SW) 但是 SELECT(SR) 还是可以的。下面是操作日志:
MySQL> lock table testsort12 read;
Query OK, 0 rows affected (0.01 sec)
2017-08-03T21:08:27.267947Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
2017-08-03T21:08:27.267979Z3[Note] (>MDL PRINT) Thread id is3:
2017-08-03T21:08:27.268009Z3[Note] (->MDL PRINT) DB_name is:test
2017-08-03T21:08:27.268040Z3[Note] (-->MDL PRINT) OBJ_name is:testsort12
2017-08-03T21:08:27.268070Z3[Note] (--->MDL PRINT) Namespaceis:TABLE
2017-08-03T21:08:27.268113Z3[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_READ_ONLY(SRO)
2017-08-03T21:08:27.268145Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
2017-08-03T21:08:27.268175Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
10、MDL_SHARED_NO_READ_WRITE(SNRW)
用于 LOCK TABLES WRITE 语句,兼容性如下:
可以看到 DML(SW) 和 SELECT(SR) 都被它堵塞,但是还可以 DESC(SH)。
操作日志记录如下:
1. `MySQL> lock table testsort12 write;
2. `Query OK, 0 rows affected (0.00 sec)
3. `2017-08-03T21:13:07.113347Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
4. `2017-08-03T21:13:07.113407Z3[Note] (>MDL PRINT) Thread id is3:
5. `2017-08-03T21:13:07.113435Z3[Note] (--->MDL PRINT) Namespaceis:GLOBAL
6. `2017-08-03T21:13:07.113458Z3[Note] (---->MDL PRINT) Fast path is:(Y)
7. `2017-08-03T21:13:07.113482Z3[Note] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX)
8. `2017-08-03T21:13:07.113505Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_STATEMENT
9. `2017-08-03T21:13:07.113604Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
10. `2017-08-03T21:13:07.113637Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
11. `2017-08-03T21:13:07.113660Z3[Note] (>MDL PRINT) Thread id is3:
12. `2017-08-03T21:13:07.113681Z3[Note] (->MDL PRINT) DB_name is:test
13. `2017-08-03T21:13:07.113703Z3[Note] (-->MDL PRINT) OBJ_name is:
14. `2017-08-03T21:13:07.113725Z3[Note] (--->MDL PRINT) Namespaceis:SCHEMA
15. `2017-08-03T21:13:07.113746Z3[Note] (---->MDL PRINT) Fast path is:(Y)
16. `2017-08-03T21:13:07.113768Z3[Note] (----->MDL PRINT) Mdl type is:MDL_INTENTION_EXCLUSIVE(IX)
17. `2017-08-03T21:13:07.113791Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
18. `2017-08-03T21:13:07.113813Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
19. `2017-08-03T21:13:07.113842Z3[Note] (acquire_lock)THIS MDL LOCK acquire ok!
20. `2017-08-03T21:13:07.113865Z3[Note] (>MDL PRINT) Thread id is3:
21. `2017-08-03T21:13:07.113887Z3[Note] (->MDL PRINT) DB_name is:test
22. `2017-08-03T21:13:07.113922Z3[Note] (-->MDL PRINT) OBJ_name is:testsort12
23. `2017-08-03T21:13:07.113945Z3[Note] (--->MDL PRINT) Namespaceis:TABLE
24. `2017-08-03T21:13:07.113975Z3[Note] (----->MDL PRINT) Mdl type is:MDL_SHARED_NO_READ_WRITE(SNRW)
25. `2017-08-03T21:13:07.113998Z3[Note] (------>MDL PRINT) Mdl duration is:MDL_TRANSACTION
26. `2017-08-03T21:13:07.114021Z3[Note] (------->MDL PRINT) Mdl status is:EMPTY
除此之外可以发现语句还需要 GLOBAL 和 SCHEMA 上的 IX 锁,换句话说 flush tables with read lock; 会堵塞‘lock table testsort12 write’,但是‘lock table testsort12 read’却不会堵塞。
11、MDL_EXCLUSIVE(X)
用于各种 DDL 操作,实际上基本全部的 DDL 都会涉及到这个锁,即便是 ONLINE DDL 也会在准备和提交阶段获取本锁,因此 ONLINE DDL 不是完全不堵塞的,只是堵塞时间很短很短,兼容性如下:
我们在验证 SU 和 SNW MDL Lock 类型的时候已经看到了操作记录,不做补充了。
==================================================================================================================================================================================
InnoDB Lock概念和分类
1.共享锁(S)和排他锁(X)
这两个锁是行级别的锁
- 共享锁允许事务持有该锁去读取行
- 排它锁允许事务持有该锁去update和delete行
2.意向锁(IS、IX)
InnoDB支持多粒度锁,允许行锁和表锁共存,这两个锁是表级别的锁;而它们的作用是避免去检查每一行是否持有(行级别的)排他/共享锁。
- 意向共享锁指明一个事务准备对单行设置共享锁
- 意向排他锁指明一个事务准备对单行设置排他锁
X |
IX |
S |
IS |
|
---|---|---|---|---|
X |
Conflict | Conflict | Conflict | Conflict |
IX |
Conflict | Compatible | Conflict | Compatible |
S |
Conflict | Conflict | Compatible | Compatible |
IS |
Conflict | Compatible | Compatible | Compatible |
注意:意向锁不会与行级别的共享/排他锁互斥,上边的兼容图表X/S代表的是表级别的排他/共享锁
3.记录锁
一个记录锁是锁在索引记录行的。(包括主键和二级索引)
4.gap锁
间隙锁,主要锁住间隙
5.next-key
它是gap锁和record锁的联合,一个表包含10, 11, 13, and 20值,则锁住范围
(negative infinity, 10] (10, 11] (11, 13] (13, 20] (20, positive infinity)
- 原则1:加锁的基本单位是next-key lock。希望你还记得,next-key lock是前开后闭区间。
- 原则2:查找过程中访问到的对象才会加锁。
- 优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁。
- 优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。
- 一个bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。
举例:select* from tt where code =6 ,锁住区间(3,6],(6,7),最后7不满足等值条件,退化成间隙锁。
引用:https://segmentfault.com/a/1190000022366564
MySQL的MDL锁的更多相关文章
- 有了MDL锁视图,业务死锁从此一目了然
摘要:MDL锁视图让一线运维人员清晰地查看数据库各session持有和等待的元数据锁信息,从而找出数据库MDL锁等待的根因,准确地进行下一步决策. 当多用户共同存取数据时,数据库中就会产生多个事务同时 ...
- 深入理解MYSQL的MDL元数据锁
1 前言 2 MDL锁与实现 3 MDL锁的性能与并发改进 4 MDL锁的诊断 前言 好久没更新,主要是因为Inside君最近沉迷于一部动画片——<新葫芦娃兄弟>.终于抽得闲,完成了本篇关 ...
- MySQL锁系列3 MDL锁
http://www.cnblogs.com/xpchild/p/3790139.html MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构 ...
- mysql 原理 ~ DDL之mdl锁
一 简介: MDL锁 二 具体 1 MDL锁 1 增删查改 申请MDL读锁 2 ddl语句 1. 拿MDL写锁 2. 降级成MDL读锁 3. 真正做DDL ...
- MySQL里面的锁
MySQL里面的锁可以分为:全局锁,表级锁,行级锁. 一.全局锁:对整个数据库实例加锁.MySQL提供加全局读锁的方法:Flush tables with read lock(FTWRL)这个命令可以 ...
- MySQL实战 | 06/07 简单说说MySQL中的锁
原文链接:MySQL实战 | 06/07 简单说说MySQL中的锁 本文思维导图:https://mubu.com/doc/AOa-5t-IsG 锁是计算机协调多个进程或纯线程并发访问某一资源的机制. ...
- 你了解MySQL中的锁吗?
MySQL中的锁,分为全局锁.表级锁.行锁 全局锁 全局锁的意思就是,对整个数据库实例加锁,它的命令是FTWRL Flash tables with read lock 这个命令的语义是,使整个库处于 ...
- 关于MySQL中的锁机制详解
锁概述 MySQL的锁机制,就是数据库为了保证数据的一致性而设计的面对并发场景的一种规则. 最显著的特点是不同的存储引擎支持不同的锁机制,InnoDB支持行锁和表锁,MyISAM支持表锁. 表锁就是把 ...
- mysql(3):锁和事务
MySQL锁的介绍 锁是数据库系统区别于文件系统的一个关键特性.锁机制用于管理对共享资源的并发访问. 表级锁 例如MyISAM引擎,其锁是表锁设计.并发情况下的读没有问题,但是并发插入时的性能要差一些 ...
- 面试官:MySQL 有哪些锁??
大家好,我是小林. 这次,来说说 MySQL 的锁,主要是 Q&A 的形式,看起来会比较轻松. 不多 BB 了,发车! 在 MySQL 里,根据加锁的范围,可以分为全局锁.表级锁和行锁三类. ...
随机推荐
- DotNetCore2.1使用GitLab通过阿里云自动构建镜像上传阿里云仓库在Docker运行
操作步骤: 1.安装GitLab并添加项目(此处省略安装过程) 2.获取GitLab的Access Tokens 3.创建空的DotNetCore2.1 Api项目 4.项目添加Docker支持,文件 ...
- 【面试题】XSS攻击是什么?
XSS攻击是什么? 要点: XSS是跨站脚本攻击.向目标网站插入恶意代码.大量用户访问网站时运行恶意脚本获取信息 答: XSS是跨站脚本攻击(Cross Site Scripting),不写为CSS是 ...
- [CSS]隐藏浏览器滚动条
::-webkit-scrollbar { display: none; /* Chrome Safari */ }
- ASP中把数据导出为Excel的三种方法
方法一:用excel组件 这种方法利用Excel组件直接导出excel文件,要求服务器端安装有微软office(Excel)程序,否则无法运行. 完整示例如下: Set conn=server.Cre ...
- 以EEPROM为例的硬件IIC的使用
目录 参考调试MPU6050与EEPROM的经验,整合了目标内存/寄存器地址是否为16位的情况,合并了单字节与多字节间的操作,添加了返回值与读写超时功能:硬件IIC的7位从机地址查询方式读写参考代码 ...
- 【Linux】有名管道实现进程间通信——一个简单聊天程序
有名管道实现简单聊天程序 1. "你来我往"式简单聊天 函数功能:简单聊天程序,两个程序a和b,a向b发送信息,b接收信息,b向a发送信息,a接收信息:... 源码参考: chat ...
- scrollIntoView()方法将元素滚动到浏览器窗口的可见区域
TIPS:容器可滚动时才有用! 语法 element.scrollIntoView(); // 等同于element.scrollIntoView(true) element.scrollIntoVi ...
- sys&faker&jsonpath模块、异常处理、多线程、多进程
1.sys模块 sys.argv 能获取运行文件时,文件名后面所传参数.结果是一个列表. import sys print(sys.argv) #获取运行python文件的时候传入的参数,会连同文件名 ...
- 莫烦Python 4
莫烦Python 4 新建模板小书匠 RNN Classifier 循环神经网络 问题描述 使用RNN对MNIST里面的图片进行分类 关键 SimpleRNN()参数 batch_input_shap ...
- SpringMVC的学习day01
什么是SpringMVC 基于狂神说SpringMVC课程的学习 前面已经学习了spring.javaSE.javaweb.mybatis等知识,今天开始学习springMVC,是ssm框架的最后一个 ...