修改表的state值_解决MDL锁导致无法操作数据库表的问题

1448e529746b7258e09cdbab3f2af580.png

背景信息

MYSQL的MDL锁,用于解决或者保证DDL操作与DML操作之间的一致性,但是在部分场景下会出现阻塞,例如执行DML操作时执行ALTER操作、存在长时间查询时执行ALTER操作等等。

表象如下:

出现 Waiting for table metadata lock 且长时间处于等待状态,并阻塞所有后续对表的操作

mysql> show processlist;
+------+-----------------+----------------------+------+---------+---------+---------------------------------+-------------------------------+
| Id   | User            | Host                 | db   | Command | Time    | State                           | Info                          |
+------+-----------------+----------------------+------+---------+---------+---------------------------------+-------------------------------+
|    1 | event_scheduler | localhost            | NULL | Daemon  | 1562471 | Waiting on empty queue          | NULL                          |
| 4280 | root            | 221.228.242.102:5585 | test | Sleep   |    1063 |                                 | NULL                          |
| 4284 | root            | 221.228.242.102:5604 | test | Sleep   |     728 |                                 | NULL                          |
| 4293 | root            | localhost            | test | Sleep   |     154 |                                 | NULL                          |
| 4294 | root            | localhost            | test | Query   |     128 | Waiting for table metadata lock | alter table t drop column d   |
| 4295 | root            | localhost            | test | Query   |       0 | starting                        | show processlist              |
| 4296 | root            | localhost            | test | Query   |       4 | Waiting for table metadata lock | insert into t(id) select null |
+------+-----------------+----------------------+------+---------+---------+---------------------------------+-------------------------------+
7 rows in set (0.03 sec)

MDL锁出现场景

  • 创建、删除索引。
  • 修改表结构。
  • 表维护操作(optimize table、repair table 等)。
  • 删除表。
  • 获取表级写锁 。

被锁原因

  • 当前有对表的长时间查询。
  • 显示或者隐式开启事务后未提交或回滚,比如查询完成后未提交或者回滚。
  • 表上有失败的查询事务。

解决办法

  • 找到魏师傅 MDL 锁的session,kill掉
  • 或 kill 掉DDL语句,等待下一次运维时间变更
select concat('kill ',i.trx_mysql_thread_id,';') from information_schema.innodb_trx i,
  (select 
         id, time
     from
         information_schema.processlist
     where
         time = (select 
                 max(time)
             from
                 information_schema.processlist
             where
                 state = 'Waiting for table metadata lock'
                 and substring(info, 1, 5) in ('alter' , 'optim', 'repai', 'lock ', 'drop ', 'creat'))
    ) p
  where timestampdiff(second, i.trx_started, now()) > p.time
  and i.trx_mysql_thread_id  not in (connection_id(),p.id);

使用有权限的用户执行`kill`即可终端问题会话,解除DML锁。

维护建议

  • 在业务低峰期执行相关场景操作,例如创建索引、删除索引等。
  • 开启事务自动提交autocommit。
  • 设置参数lock_wait_timeout为较小值。
  • 考虑使用事件来终止长时间运行的事务,比如下面的例子中会终止执行时间超过60分钟的事务。
create event my_long_running_trx_monitor
on schedule every 60 minute
starts '2015-09-15 11:00:00'
on completion preserve enable do
begin
  declare v_sql varchar(500);
  declare no_more_long_running_trx integer default 0; 
  declare c_tid cursor for
    select concat ('kill ',trx_mysql_thread_id,';') 
    from information_schema.innodb_trx 
    where timestampdiff(minute,trx_started,now()) >= 60;
  declare continue handler for not found
    set no_more_long_running_trx=1;
  open c_tid;
  repeat
    fetch c_tid into v_sql;
 set @v_sql=v_sql;
 prepare stmt from @v_sql;
 execute stmt;
 deallocate prepare stmt;
  until no_more_long_running_trx end repeat;
  close c_tid;
end;

示例

场景1-有对表的长时间查询

data_million_large 当前有 800万+的数据,对表进行一次全表查询肯定是条慢SQL

d8a3a5db432a9de9b4324a8942b66081.png
mysql> show processlist;
+----+-----------------+----------------------+-------+---------+------+---------------------------------+------------------------------------------------------------+
| Id | User            | Host                 | db    | Command | Time | State                           | Info                                                       |
+----+-----------------+----------------------+-------+---------+------+---------------------------------+------------------------------------------------------------+
|  1 | event_scheduler | localhost            | NULL  | Daemon  |  106 | Waiting on empty queue          | NULL                                                       |
|  3 | root            | 221.228.242.102:7645 | ytest | Sleep   |   97 |                                 | NULL                                                       |
|  4 | root            | 221.228.242.102:7646 | ytest | Sleep   |   94 |                                 | NULL                                                       |
|  5 | root            | 221.228.242.102:7647 | ytest | Sleep   |   93 |                                 | NULL                                                       |
|  6 | root            | 221.228.242.102:7648 | ytest | Query   |   90 | Sending to client               | select * from data_million_large                           |
|  7 | root            | 221.228.242.102:7660 | ytest | Query   |   77 | Waiting for table metadata lock | alter table data_million_large add column abcd varchar(10) |
|  8 | root            | 221.228.242.102:7663 | ytest | Sleep   |   40 |                                 | NULL                                                       |
|  9 | root            | 221.228.242.102:7669 | ytest | Sleep   |   55 |                                 | NULL                                                       |
| 10 | root            | 221.228.242.102:7674 | ytest | Query   |   46 | Waiting for table metadata lock | select * from data_million_large limit 1                   |
| 11 | root            | localhost            | NULL  | Query   |    0 | starting                        | show processlist                                           |
+----+-----------------+----------------------+-------+---------+------+---------------------------------+------------------------------------------------------------+
10 rows in set (0.00 sec)

场景2-事务未提交或回滚

dd91839d94e072ee5bf4f2d0e3bc3c06.png
mysql> show processlist;
+----+-----------------+----------------------+-------+---------+------+---------------------------------+-----------------------------------------------------------+
| Id | User            | Host                 | db    | Command | Time | State                           | Info                                                      |
+----+-----------------+----------------------+-------+---------+------+---------------------------------+-----------------------------------------------------------+
|  1 | event_scheduler | localhost            | NULL  | Daemon  | 1658 | Waiting on empty queue          | NULL                                                      |
| 15 | root            | 221.228.242.102:8652 | ytest | Sleep   |   64 |                                 | NULL                                                      |
| 16 | root            | 221.228.242.102:8669 | ytest | Query   |   23 | Waiting for table metadata lock | alter table data_million_large add column aaa varchar(10) |
| 17 | root            | 221.228.242.102:8671 | ytest | Query   |   13 | Waiting for table metadata lock | select * from data_million_large limit 1                  |
| 18 | root            | 221.228.242.102:8676 | ytest | Sleep   |   10 |                                 | NULL                                                      |
| 19 | root            | localhost            | NULL  | Query   |    0 | starting                        | show processlist                                          |
+----+-----------------+----------------------+-------+---------+------+---------------------------------+-----------------------------------------------------------+
6 rows in set (0.00 sec)

场景3-有失败的查询事务

1935a1315688573f564612feb2a37468.png
mysql> show processlist;
+----+-----------------+----------------------+-------+---------+------+---------------------------------+-----------------------------------------------------------+
| Id | User            | Host                 | db    | Command | Time | State                           | Info                                                      |
+----+-----------------+----------------------+-------+---------+------+---------------------------------+-----------------------------------------------------------+
|  1 | event_scheduler | localhost            | NULL  | Daemon  | 2305 | Waiting on empty queue          | NULL                                                      |
| 15 | root            | 221.228.242.102:8652 | ytest | Sleep   |  468 |                                 | NULL                                                      |
| 17 | root            | 221.228.242.102:8671 | ytest | Sleep   |  476 |                                 | NULL                                                      |
| 18 | root            | 221.228.242.102:8676 | ytest | Sleep   |  657 |                                 | NULL                                                      |
| 19 | root            | localhost            | NULL  | Query   |    0 | starting                        | show processlist                                          |
| 21 | root            | 221.228.242.102:8744 | ytest | Sleep   |  476 |                                 | NULL                                                      |
| 23 | root            | localhost            | ytest | Sleep   |   83 |                                 | NULL                                                      |
| 24 | root            | localhost            | ytest | Query   |   27 | Waiting for table metadata lock | alter table data_million_large add column bbb varchar(10) |
| 25 | root            | localhost            | ytest | Query   |    3 | Waiting for table metadata lock | select * from data_million_large limit 1                  |
+----+-----------------+----------------------+-------+---------+------+---------------------------------+-----------------------------------------------------------+
9 rows in set (0.01 sec)

这个示例最难排查,咋一看没有任何阻塞的事务存在,持有MDL锁的session已处于 Sleep 状态了

查看session最后一次执行的语句

可查看session执行的最后一次语句的记录,包括错误的信息

# 若同一session下执行错误,继续执行其他操作,则错误信息会被覆盖
mysql> select * from performance_schema.events_statements_current where errors=1G
*************************** 1. row ***************************
              THREAD_ID: 49
               EVENT_ID: 49
           END_EVENT_ID: 49
             EVENT_NAME: statement/sql/select
                 SOURCE: 
            TIMER_START: 2226273809177000
              TIMER_END: 2226273972864000
             TIMER_WAIT: 163687000
              LOCK_TIME: 0
               SQL_TEXT: select qwer from data_million_large limit 1
                 DIGEST: deeb24ced596fc26212e71be9d90cb47
            DIGEST_TEXT: SELECT `qwer` FROM `data_million_large` LIMIT ? 
         CURRENT_SCHEMA: ytest
            OBJECT_TYPE: NULL
          OBJECT_SCHEMA: NULL
            OBJECT_NAME: NULL
  OBJECT_INSTANCE_BEGIN: NULL
            MYSQL_ERRNO: 1054
      RETURNED_SQLSTATE: 42S22
           MESSAGE_TEXT: Unknown column 'qwer' in 'field list'
                 ERRORS: 1
               WARNINGS: 0
          ROWS_AFFECTED: 0
              ROWS_SENT: 0
          ROWS_EXAMINED: 0
CREATED_TMP_DISK_TABLES: 0
     CREATED_TMP_TABLES: 0
       SELECT_FULL_JOIN: 0
 SELECT_FULL_RANGE_JOIN: 0
           SELECT_RANGE: 0
     SELECT_RANGE_CHECK: 0
            SELECT_SCAN: 0
      SORT_MERGE_PASSES: 0
             SORT_RANGE: 0
              SORT_ROWS: 0
              SORT_SCAN: 0
          NO_INDEX_USED: 0
     NO_GOOD_INDEX_USED: 0
       NESTING_EVENT_ID: NULL
     NESTING_EVENT_TYPE: NULL
    NESTING_EVENT_LEVEL: 0
1 row in set (0.07 sec)
参考文档: https:// help.aliyun.com/knowled ge_detail/94566.html#concept-csn-5tt-4fb
《MySQL DBA甩锅技巧集锦-张沈波》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值