近期客户的MySql slave在备份的时候,长时间卡住不动,经过查询是因为在备份的时候,发起了一个dml事务,导致等待。于是分析了一下
MySql 5.7
备份的时候会锁,导致数据库无法正常DML
MySQL锁的分类有很多种,其中根据影响范围来划分主要分为全局锁、表锁、行锁。
MySQL锁实现
MySQL数据库里面的锁是基于索引实现的,在Innodb中锁都是作用在索引上面的,当SQL命中索引时,那么锁住的就是命中条件内的索引节点(行锁),如果没有命中索引的话,那我们锁的就是整个索引树(表锁)。
全局读锁
MySQL 全局锁会申请一个全局的读锁,对整个库加锁。
1.备份时为了得到一致性备份,可能会添加全局读锁。
2.主从复制架构下,主备切换可能会用到全局读锁。
全局锁的实现方式有两种:
//第一种方法Flush tables with read lock(FTWRL)
//第二种方法set global readonly=true
当数据库处于全局锁的状态时,其他线程的以下语句会被阻塞:
数据更新语句(数据的增删改)、数据定义语句(建表、索引变更、修改表结构等)和更新类事务的提交语句。
释放全局锁
unlock tables;
全局读锁问题分析
在MySQL5.7之前的版本,要排查谁持有全局读锁,通常在数据库层面是很难直接查询到有用数据的(innodb_locks表也只能记录InnoDB层的锁信息,而全局读锁是Server层的锁,所以无法查询到)。
从MySQL5.7版本开始提供了 performance_schema.metadata_locks表,用来记录一下Server层的锁信息(包括全局读锁和MDL锁等)。
下面通过示例演示如何找出谁持有全局锁:
数据库版本MySQL5.7.35
MySQL [cjcdb]> select version();
+------------+
| version() |
+------------+
| 5.7.35-log |
+------------+
1 row in set (0.00 sec)
创建测试数据
MySQL [cjcdb]> create table t1(id int,age int);
Query OK, 0 rows affected (0.04 sec)
MySQL [cjcdb]> insert into t1 values(1,100),(2,30),(3,80);
Query OK, 3 rows affected (0.03 sec)
Records: 3 Duplicates: 0 Warnings: 0
MySQL [(none)]> update performance_schema.setup_instruments set enabled = 'YES' where name like '%lock%';
Query OK, 173 rows affected (6.27 sec)
Rows matched: 180 Changed: 173 Warnings: 0
#打开一个会话
MySQL [cjcdb]> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 11 |
+-----------------+
1 row in set (0.00 sec)
#全局锁