metadata lock

1 锁等待的例子

session 1: 执行查询但不提交

mysql> begin;

mysql> select * from test where c2 = ‘1‘;

session 2: 执行ddl发生等待

mysql> alter table test drop index idx5;

查看show processlist;

| 20487 | mytest | ****:35986 | test123 | Sleep | 3799 | | NULL |
| 20501 | mytest | ****:35990 | test123 | Sleep | 65 | | NULL |
| 20886 | mytest | ****:36076 | test123 | Query | 36 | Waiting for table metadata lock | alter table test drop index idx5 |
| 21463 | mytest | ****:36208 | NULL | Query | 0 | init | show processlist |

ddl发生锁等待"Waiting for table metadata lock"

从information_schema.innodb_trx可以查到未提交的事务

mysql> select * from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 96386
trx_state: RUNNING
trx_started: 2015-01-29 16:34:38
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 0
trx_mysql_thread_id: 20501
trx_query: NULL
trx_operation_state: NULL
trx_tables_in_use: 0
trx_tables_locked: 0
trx_lock_structs: 0
trx_lock_memory_bytes: 360
trx_rows_locked: 0
trx_rows_modified: 0
trx_concurrency_tickets: 0
trx_isolation_level: READ COMMITTED
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 10000
trx_is_read_only: 0
trx_autocommit_non_locking: 0
1 row in set (0.00 sec)

show engine innodb status也可看到未提交事务信息。

------------
TRANSACTIONS
------------
Trx id counter 96455
Purge done for trx‘s n:o < 96339 undo n:o < 0 state: running but idle
History list length 282
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 21463, OS thread handle 0x2b7e50081700, query id 155157 10.189.100.29 mytest init
show engine innodb status
---TRANSACTION 96330, not started
MySQL thread id 20886, OS thread handle 0x2b7e600c2700, query id 153866 10.189.100.30 mytest Waiting for table metadata lock
alter table test drop index idx5
---TRANSACTION 96094, not started
MySQL thread id 20487, OS thread handle 0x2b7e8c081700, query id 146859 10.189.100.29 mytest cleaning up
---TRANSACTION 96386, ACTIVE 744 sec
MySQL thread id 20501, OS thread handle 0x2b7e70081700, query id 153813 10.189.100.30 mytest cleaning up

session 1:执行commit;

commit;

session 2:ddl完成。

2 metadata lock

1)metadata lock是什么

顾名思义,metadata lock即元数据锁。在数据库中元数据即数据字典信息包括db,table,function,procedure,trigger,event等。metadata lock主要为了保证元数据的一致性。而实际上metadata lock不仅仅保护元数据,还可以保证set global read only, flush tables with read lock 操作的顺利执行。

metadata lock也是一种锁。每个metadata lock都会定义锁住的对象,锁的持有时间和锁的类型

锁的作用对象 

metadata lock按锁住的对象来分类,可以分为global, schema, table, function,procedure,trigger,event,commit.这些对象发生锁等待时,我们在show processlist可以分别看到如下等待信息。

Waiting for global read lock
 Waiting for schema metadata lock
 Waiting for table metadata lock
 Waiting for stored function metadata lock
 Waiting for stored procedure metadata lock
 Waiting for trigger metadata lock
 Waiting for event metadata lock
 Waiting for commit lock

锁的持有时间

MDL_STATEMENT:语句结束时释放
MDL_TRANSACTION:事务结束时释放
MDL_EXPLICIT:显式释放

锁的类型

(1)MDL_INTENTION_EXCLUSIVE(IX):意向排他锁,用于global和commit的加锁。

例如:truncate table t1;insert into t1 values(3,‘abcde‘);会加如下锁:

(GLOBAL,MDL_STATEMENT,MDL_INTENTION_EXCLUSIVE)

(SCHEMA,MDL_TRANSACTION,MDL_INTENTION_EXCLUSIVE)

(2)MDL_SHARED(S):只访问元数据,不访问数据。

例如: set golbal_read_only =on;flush tables with read lock;会加如下锁:

(GLOBAL,MDL_EXPLICIT,MDL_SHARED)

(COMMIT,MDL_EXPLICIT,MDL_SHARED)

(3)MDL_SHARED_HIGH_PRIO(SH):用于访问information_scheam表,不涉及数据。

例如: select * from information_schema.tables;

show create table xx;

desc xxx;会加如下锁:

(TABLE,MDL_TRANSACTION,MDL_SHARED_HIGH_PRIO)

(4)MDL_SHARED_READ(SR): 用于读数据

例如:select * from t1; lock table t1 read;会加如下锁:

(TABLE,MDL_TRANSACTION,MDL_SHARE_READ)

(5)MDL_SHARED_WRITE(SW):用于写数据

例如:insert/update/delete/select .. for update会加如下锁:

(TABLE,MDL_TRANSACTION,MDL_SHARE_WRITE)

(6)MDL_SHARED_UPGRADABLE(SU):是mysql5.6引入的新的Metadata lock,在alter table /create index/drop index会加该锁;可以说是为了online ddl才引入的。特点是允许DML,防止DDL;

(TABLE,MDL_TRANSACTION,MDL_SHARED_UPGRADABLE)
MDL_SHARED_NO_WRITE(SNW):用于防止其他人读写数据,但可以访问元数据。

(7)MDL_SHARED_NO_WRITE(SNW):用于防止其他人读写数据,但可以访问元数据。

alter table t1 modify c bigint;(非onlineddl)

(TABLE,MDL_TRANSACTION,MDL_SHARED_NO_WRITE)

(8)MDL_SHARED_NO_READ_WRITE(SNRW):用于防止其他人读写数据,但可以访问元数据。

lock table t1 write;

(TABLE,MDL_TRANSACTION,MDL_SHARED_NO_READ_WRITE)

(9)MDL_EXCLUSIVE(X):防止访问元数据

例如:CREATE/DROP/RENAME TABLE,其他online DDL在rename阶段也持有X锁

(TABLE,MDL_TRANSACTION,MDL_EXCLUSIVE)

other

关于global对象

主要作用是防止DDL和写操作的过程中,执行set golbal_read_only =on或flush tables with read lock;

关于commit对象锁

主要作用是执行flush tables with read lock后,防止已经开始在执行的写事务提交。

insert/update/delete在提交时都会上(COMMIT,MDL_EXPLICIT,MDL_INTENTION_EXCLUSIVE)锁。

关于schema对象锁

主要作用是防止alter/drop/create db与 alter/drop/create table,procedut之间的并发执行

alter/drop/create db会上(SCHEMA,MDL_TRANSACTION,MDL_EXCLUSIVE)

而 alter/drop/create table,procedut会上(SCHEMA,MDL_TRANSACTION,MDL_INTENTION_EXCLUSIVE)

关于table对象锁

主要处理表DDL与DDL, 表DDL与表DML之间的并发

3 其他案例

根据前面介绍的metadata lock加锁规则和锁的兼容性,我们就可以解释出现metadata lock等待的原因了。

1)Waiting for global read lock

我们先够造一个Waiting for global read lock场景:

session1: alter table t1 add c3 bigint; //大表执行需较长时间

session2: set global read only=on; //等待

查看

mysql> show processlist;
+----+------+-----------------+------+---------+------+------------------------------+------------------------------+
| Id | User | Host            | db   | Command | Time | State                        | Info                         |
+----+------+-----------------+------+---------+------+------------------------------+------------------------------+
|  1 | root | localhost:5202  | test | Query   |   12 | altering table               | alter table t1 add c3 bigint |
|  2 | root | localhost:14699 | test | Query   |    3 | Waiting for global read lock | set global read_only=on      |
|  3 | root | localhost:17085 | NULL | Query   |    0 | init                         | show processlist             |
+----+------+-----------------+------+---------+------+------------------------------+------------------------------+
3 rows in set (0.00 sec)

分析

alter table t1 add c3 bigint;会加(GLOBAL,MDL_STATEMENT,MDL_INTENTION_EXCLUSIVE) 语句结束后才释放

set global read only=on;会加(GLOBAL,MDL_EXPLICIT,MDL_SHARED)

由于session1执行时间比较长,一直持有MDL_INTENTION_EXCLUSIVE。从兼容性矩阵可以看出MDL_SHARED和MDL_INTENTION_EXCLUSIVE是不相容的,因此发生“Waiting for global read lock ”等待。直到session 1 alter操作完成释放MDL_INTENTION_EXCLUSIVE。set global read only=on;才可以继续执行。

2)Waiting for commit lock

session1: begin

insert into t1 vlaues(null, ‘ab‘);

session2:flush table with read lock;//成功

session1: commit //发生等待

查看

mysql> show processlist;
+----+------+-----------------+------+---------+------+-------------------------+------------------+
| Id | User | Host            | db   | Command | Time | State                   | Info             |
+----+------+-----------------+------+---------+------+-------------------------+------------------+
|  1 | root | localhost:5202  | test | Query   |    7 | Waiting for commit lock | commit           |
|  2 | root | localhost:14699 | test | Sleep   |   13 |                         | NULL             |
|  3 | root | localhost:17085 | NULL | Query   |    0 | init                    | show processlist |
+----+------+-----------------+------+---------+------+-------------------------+------------------+


分析

 flush table with read lock;持有(COMMIT,MDL_EXPLICIT,MDL_SHARED)

commit时上(COMMIT,MDL_EXPLICIT,MDL_INTENTION_EXCLUSIVE)锁

MDL_SHARED和MDL_INTENTION_EXCLUSIVE是不相容的,因此发生等待

3)Waiting for table metadata lock

这里我们来看第一节给出的锁等待的例子。

查询表时上(TABLE,MDL_TRANSACTION,MDL_SHARE_READ)锁,这里需注意MDL_TRANSACTION表示事物提交时才释放锁。

alter表上(TABLE,MDL_TRANSACTION, MDL_EXCLUSIVE)锁,MDL_SHARE_READ和MDL_EXCLUSIVE是不相容的,因此需等待查询事物提交。

时间: 2024-12-29 23:45:03

metadata lock的相关文章

RDS MySQL 表上 Metadata lock 的产生和处理

1. Metadata lock wait 出现的场景 2. Metadata lock wait 的含义 3. 导致 Metadata lock wait 等待的活动事务 4. 解决方案 5. 如何避免出现长时间 Metadata lock wait 导致表上相关查询阻塞,影响业务 1. Metadata lock wait 出现的场景 创建.删除索引 修改表结构 表维护操作(optimize table.repair table 等) 删除表 获取表上表级写锁 (lock table tab

MySQL出现Waiting for table metadata lock的原因以及解决方法

转自:http://ctripmysqldba.iteye.com/blog/1938150 (有修改) MySQL在进行alter table等DDL操作时,有时会出现Waiting for table metadata lock的等待场景.而且,一旦alter table TableA的操作停滞在Waiting for table metadata lock的状态,后续对TableA的任何操作(包括读)都无法进行,因为他们也会在Opening tables的阶段进入到Waiting for

MySQL metadata lock

什么是元数据 描述数据库中的数据的数据都是元数据,如库名.表明.列名.版本名,和show语句展示的大多数内容都是元数据,以及在information_shema中记录数据库对象的表中的内容也是元数据 为什么MySQL要设置元数据锁 为了保证可以并发访问数据库对象及保证数据的一致性,所以应用metadata lock,如session1正在扫描t表数据,此会话持有t表的元数据锁,这时session2话尝试要drop t表,在尝试获取t表元数据锁的时候被阻塞,假如没有MDL的设计,那么在sessio

mysql metadata lock锁

很多情况下,很多问题从理论上或者管理上而言都是可以避免或者说很好解决的,但是一旦涉及到现实由于管理或者协调或者规范执行的不够到位,就会出现各种各样本不该出现的问题,这些问题的通常在生产环境并不会出现,但是现实是无论在任何环节出现,都得去找到解决方法,很多时候原因是一部分,预防措施也是一部分,但解决方法也是必须的,因为不可能跟所有的开发人员说你按照我说的做就没有问题了,因为总会有人疏忽了或者忽视了. 前两天,测试环境升级脚本,跑到一半就报锁超时了,好几次后测试让协助而解决下.看了下,是个trunc

Waiting for table metadata lock

本篇博客准备分两部分详细的介绍一下mysql (基于mysql 5.6)中的metadata lock, 一. 官方文档中关于Metadata Locking描述(5.6) 8.11.4 Metadata Locking MySQL uses metadata locking to manage concurrent access to database objects and to ensure data consistency. Metadata locking applies not ju

mysql metadata lock(二)

上一篇<mysql metadata lock(一)>介绍了为什么引入MDL,MDL作用以及MDL锁导致阻塞的几种典型场景,文章的最后还留下了一个小小的疑问.本文将更详细的介绍MDL,主要侧重介绍MDL的原理和实现.一般而言,商业数据库系统实现锁,一般将锁划分为读锁(共享锁)和写锁(排它锁),为了进一步提高并发性,还会加入意向共享锁和意向排它锁.但是偏偏mysql的MDL搞地比较复杂,但目的也是为了提高并发度.MDL包含有9种类型,详细参考表1.主要其实也是两大类,只是对共享锁做了进一步细分.

mysql错误: waiting for table metadata lock

今天突然发现truncate一个表都慢到不行,于是 SHOW PROCESSLIST 发现错误:waiting for table metadata lock解决方法:查看information_schema.INNODB_TRX拥有事务的trx_mysql_thread_id,kill trx_mysql_thread_id回滚事务

MySQL metadata lock阻塞问题

2017年4月1日星期六 在某个业务的主库加完2个字段后,业务方反馈在30分钟后从库也一直无法查看到这个新字段. 在slave上执行show slave status\G 如下图 show porcesslist; 如下图: 上图2张图,可以看到延迟较大,从库上的alter操作一直在等待metadata lock,处于阻塞状态. 解决方法: 使用SELECT * FROM information_schema.innodb_trx\G找到那个事务未提交导致的问题: kill2359; 杀掉这个线

Mysql事物与Metadata lock 问题

环境说明: MySQL 5.6.16 OS:Linux RedHat 6.2 64bit 1.问题描述 目前新上一个使用MySQL数据库项目,在数据库中,每隔5分钟做truncate某个表操作,经常出现metadata lock锁等待,导致后面的对这个表的所有操作(包括读)全部metadata lock等待.严重影响了数据库运行. 且metadata lock锁等待不同于普通的行级锁,等待超时时间默认为365天,而普通的行级锁超时是120s mysql> show variables like