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 just to tables, but also to schemas and stored programs (procedures, functions, triggers, and scheduled events).  >>mysql使用metadata locking来保证数据库对象并发访问时的数据一致性。metadata locking不仅仅用来保护表,也用来保护数据库中的其他对象,比如说 schemas,procedures,functions,triggers,scheduled events。

Metadata locking does involve some overhead, which increases as query volume increases. Metadata contention increases the more that multiple queries attempt to access the same objects.  >>随着访问量的增加,metadata locking所导致的开销也会增加。越多的查询访问相同的对象,产生metadata lock争用的可能越大。
Metadata locking is not a replacement for the table definition cache, and its mutexes and locks differ from the LOCK_open mutex. The following discussion provides some information about how metadata locking works.  >>metedata locking 不能代替 table definition cache。下面讨论了metadata locking如何工作。

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.  >>为了确保事物的串行(同一个对象上),如果一个对象正在被一个未结束的事物使用(显示或者隐示),那么就不能允许其他的会话对其进行ddl操作。mysql通过在事物过程中给对象加上metadata lock来实现对象的串行访问(metadata lock在事物结束的时候被释放)。如果一个表被加上了metadata lock,那么对该表的ddl操作会被阻塞(阻塞ddl,就像“元数据锁”这个名称锁说的那样)。

This principle applies not only to transactional tables, but also to nontransactional tables. Suppose that a session begins a transaction that uses transactional table t and nontransactional table nt as follows: >>上面说的metadata lock原则不仅针对事物表(如果innodb表),对非事物表(如myisam表)一样有效。假设一个会话开启了如下事物(事物中使用到了事物表t和非事物表nt)

START TRANSACTION;
SELECT * FROM t;
SELECT * FROM nt;
The server holds metadata locks on both t and nt until the transaction ends. If another session attempts a DDL or write lock operation on either table, it blocks until metadata lock release at transaction end. For example, a second session blocks if it attempts any of these operations:  >>上面的例子中mysql会对事物表t和非事物表nt都加上metadata lock直到事物结束。如果上面的事物还没有结束时,在另一个会话中进行如下操作(对t和nt进行ddl),会发现相关ddl操作都会被阻塞

DROP TABLE t;
ALTER TABLE t ...;
DROP TABLE nt;
ALTER TABLE nt ...;
LOCK TABLE t ... WRITE;
If the server acquires metadata locks for a statement that is syntactically valid but fails during execution, it does not release the locks early. Lock release is still deferred to the end of the transaction because the failed statement is written to the binary log and the locks protect log consistency  >>如果一个语法正确的语句,在执行过程中失败,加在该表上的metadata lock并不会立即释放,而是等到事物结束的时候才会释放(后面我会举例)。上面表红部分不能理解是什么意思,执行失败的语句怎么会记录到binlog中?

In autocommit mode, each statement is in effect a complete transaction, so metadata locks acquired for the statement are held only to the end of the statement.  >>在autocommit模式下,每一个语句实际上就是一个完整的事物,所以metadata lock在语句开始的时候被加上,在语句结束的时候被释放

Metadata locks acquired during a PREPARE statement are released once the statement has been prepared, even if preparation occurs within a multiple-statement transaction.  >>prepare语句获得的metadata lock在sql已经被prepare后就会被释放,即使是在一个由多个sql组成的事物中。

Before MySQL 5.5, when a transaction acquired the equivalent of a metadata lock for a table used within a statement, it released the lock at the end of the statement. This approach had the disadvantage that if a DDL statement occurred for a table that was being used by another session in an active transaction, statements could be written to the binary log in the wrong order.  >>在mysql 5.5之前,会在sql执行的过程中对表加一个类似metadata lock的锁,当语句结束的时候失败该锁(现在是在整个事物过程中加metadata lock,但是在autocommit模式下,也是在语句执行过程中加锁,执行结束后释放,因为一个语句即一个事物)。这种方法有一个缺点,可能会导致binlog记录顺序跟实际执行顺序不一致。

 

 

 

 

 

二. mysql 中出现Waiting for table metadata lock的场景

   在show processlist时我们可能见到过某个语句处于Waiting for table metadata lock状态,现在我们来分析一下,在哪些情况下会出现Waiting for table metadata lock

场景1:

  当一个表在被一个未结束的事物使用(包括select),另一个会话中对该表进行ddl操作时,因为无法获得独占的metadata lock该ddl操作会被阻塞,此时show processlist查看ddl操作处于Waiting for table metadata lock状态。这时我们希望知道是什么阻塞了我的ddl语句,通过下面三步,你就能找到是什么操作阻塞了你的ddl操作:

1)show processlist

  如果对ddl语句造成阻塞的语句正在执行中,你通过show processlist能够发现这样的语句(查看对ddl语句中所涉及表的操作)。

2)information_schema.innodb_trx

  查看innodb事物表information_schema.innodb_trx,如果在一个显示事物中(使用start transaction或者begin开启的事物),对于相关表的操作已经完成(所以show processlist无法查看到该操作),但是该事物没有被提交,此时在另一个会话中对该表进行ddl操作时,因为无法获得独占的metadata lock,该ddl操作会被阻塞。此时通过查看information_schema.innodb_trx表可以看到有活跃的事物

3)performance_schema.events_statements_current/history/history_long

  如果某个表的ddl操作因为无法获得独占的metadata lock而被阻塞,并且查看1)和2)中的方法都没有查到相关信息,那么还有一种可能是因为在一个显式的事务中,对表a进行了一个失败的操作(比如查询了一个不存在的字段),这时事务没有开始,但是失败语句获取到的锁依然有效。从performance_schema.events_statements_current表中可以查到失败的语句。events_statements_current表记录了数据库当前thread最近一次执行的sql。我们可以通过如下语句获得事务线程最近执行的语句

set group_concat_max_len=1024*10;
SELECT 
    p.*,    
    th.thread_id,
    t.trx_started,
    t.trx_rows_locked,
    t.trx_rows_modified,
    t.trx_is_read_only,
    NOW() now_time,
    (select group_concat(sql_text order by EVENT_ID SEPARATOR ';\n') from performance_schema.events_statements_history cur  where cur.thread_id=th.thread_id) trx_statements   
FROM
    information_schema.innodb_trx t
        INNER JOIN
    information_schema.processlist p ON t.trx_mysql_thread_id = p.id
        join performance_schema.threads th  on p.id=th.processlist_id;

##使用该语句的前提是

1)开启了 performance_schema(performance_schema=1);

2)update performance_schema.setup_consumers set ENABLED='yes' where name like 'events_statements%'; update performance_schema.setup_instruments set enabled='yes',timed='yes' where name like 'statement%';

 

场景2:

  我们知道metadata lock是用来保护数据结构的,如果表a正在被一个活跃的事物使用,另一个会话对表a的ddl操作会被阻塞。当表a的ddl操作因为无法获得独占的metadata lock(Waiting for table metadata lock)被阻塞时,后续对于表a的任何操作都会被阻塞,包括select操作(状态为Waiting for table metadata lock)

 

场景3:

  inplace(当然5.6开始多数的ddl操作都支持online_ddl)方式对表a执行的ddl ,在ddl语句执行过程中会阻塞对于表a的所有dml操作。在online_ddl过程中不是在整个语句执行过程对表a加独占的metadata lock,在After table(online_ddl具体过程见下图),会获取metadata lock的独占锁,当进行到altering table(也是最耗时的一步)时,所有dml都是可以正常进行的。

下面是online_ddl的处理过程(profile)

 

+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.000119 |
| checking permissions           | 0.000013 |
| checking permissions           | 0.000011 |
| init                           | 0.000007 |
| Opening tables                 | 0.007743 |
| setup                          | 0.000055 |
| creating table                 | 0.004871 |
| After create                   | 0.000152 |
| System lock                    | 0.000018 |
| preparing for alter table      | 0.009417 |
| altering table                 | 0.064343 |
| committing alter table to stor | 0.024200 |
| end                            | 0.000025 |
| query end                      | 0.002839 |
| closing tables                 | 0.000017 |
| freeing items                  | 0.000040 |
| cleaning up                    | 0.000025 |
+--------------------------------+----------+

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渔夫数据库笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值