MySQL:Waiting for table flush,blocker与表锁

主要内容

所有操作基于mysql8.0

操作顺序:
id 257 – lock table users read;
id 258 – flush tables;
id 259 – select * from users

mysql> show processlist;
+-----+-----------------+----------------+--------------------+---------+--------+-------------------------+---------------------+
| Id  | User            | Host           | db                 | Command | Time   | State                   | Info                |
+-----+-----------------+----------------+--------------------+---------+--------+-------------------------+---------------------+
|   5 | event_scheduler | localhost      | NULL               | Daemon  | 773583 | Waiting on empty queue  | NULL                |
| 257 | test            | localhost:7117 | testdb             | Sleep   |   1933 |                         | NULL                |
| 258 | root            | localhost:7226 | NULL               | Query   |   6401 | Waiting for table flush | flush tables        |
| 259 | root            | localhost:7324 | testdb             | Query   |   6349 | Waiting for table flush | select * from users |
| 261 | root            | localhost:7332 | performance_schema | Query   |      0 | init                    | show processlist    |
+-----+-----------------+----------------+--------------------+---------+--------+-------------------------+---------------------+
5 rows in set (0.00 sec)

从操作者的角度可以知道,Waiting for table flush的源头是id 257,但如果是其他人,可能就第一眼看出是id 257造成(虽然生产中一般不会有lock table操作出现)。
这位博主 (https://blog.csdn.net/feijiges/article/details/77430806) 讲的非常清楚了,其中提到innotop可以查看表锁信息,但innotop又是如何查到的表锁信息的?

在几个关于lock与wait的视图并查不到相关锁或锁等待信息,比如:
sys.innodb_lock_waits
sys.schema_table_lock_waits;
sys.x$innodb_lock_waits
performance_schema.data_lock_waits
performance_schema.data_locks
这就比较苦恼了。

最后查到performance_schema.table_handles中有INTERNAL_LOCK,EXTERNAL_LOCK等信息。table_handles表 是Table locks and lock requests的相关信息,接着就是查看文档的时候了:

table_handles:
The Performance Schema exposes table lock information through the table_handles table to show the table locks currently in effect for each opened table handle. table_handles reports what is recorded by the table lock instrumentation. This information shows which table handles the server has open, how they are locked, and by which sessions.
//performance schema通过table_handles表来揭露表锁信息,显示当前对每个打开的表句柄有效的表锁。

The table_handles table is read only and cannot be updated. It is autosized by default; to configure the table size, set the performance_schema_max_table_handles system variable at server startup.
Table lock instrumentation uses the wait/lock/table/sql/handler instrument, which is enabled by default.

这个性能表中的两个字段:
INTERNAL_LOCK -- SQL层级上的表锁使用. 其值是下列值的其中一个:READ, READ WITH SHARED LOCKS, READ HIGH PRIORITY, READ NO INSERT, WRITE ALLOW WRITE, WRITE CONCURRENT INSERT, WRITE LOW PRIORITY, WRITE. 
EXTERNAL_LOCK -- 存储引擎层级上使用的表锁,其值是READ EXTERNAL或WRITE EXTERNAL中的一个。

于是拼写了一个SQL,查看Waiting for table flush现象时的表锁情况:

select thr.PROCESSLIST_ID,thr.thread_id,p.COMMAND,p.TIME,p.STATE,p.INFO,thl.OBJECT_TYPE,thl.OBJECT_SCHEMA,thl.OBJECT_NAME,thl.INTERNAL_LOCK,thl.EXTERNAL_LOCK from performance_schema.threads thr inner join performance_schema.table_handles thl  on  thr.thread_id=thl.OWNER_THREAD_ID  inner join performance_schema.processlist p on p.id=thr.processlist_id where thl.EXTERNAL_LOCK is not null or thl.internal_lock is not null;

另外记录几点:

1. mysqldump在–flush-logs 或–master-data 时会触发flush tables.

在当进行长时间查询时,单独使用mysqldump --single-transaction并不会出现等待情况,但如果使用了–flush-logs戒–master-data后,再单独使用–single-transaction就会出现阻塞。这里面的机制有点费解。不过,只要kill最源头的查询,即可解决这些问题。

2. lock table造成的表锁的释放

在id 257 上进行commit,并不能释放锁,目前发现两种方法可释放lock table造成的表锁:1) 在锁表的当前会话中执行unlock tables;2) kill 锁表的会话。而长时间的查询,只要相关会话取消该查询即可释放,当然kill该会话也可释放。

3. 在mysql命令行中执行flush logs操作并不会被长时间查询或lock table阻塞

4. 奇怪的是在执行后select *,sleep(10000) from users后,表锁信息是:

	+----------------+-----------+---------+------+------------+----------------------------------+-------------+---------------+-------------+---------------+---------------+
	| PROCESSLIST_ID | thread_id | COMMAND | TIME | STATE      | INFO                             | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | INTERNAL_LOCK | EXTERNAL_LOCK |
	+----------------+-----------+---------+------+------------+----------------------------------+-------------+---------------+-------------+---------------+---------------+
	|            266 |       306 | Query   |    8 | User sleep | select *,sleep(10000) from users | TABLE       | testdb        | users       | NULL          | READ EXTERNAL |
	+----------------+-----------+---------+------+------------+----------------------------------+-------------+---------------+-------------+---------------+---------------+

5. sleep(n)函数(从效果看,是要等待的时间= 行数*n的时间),也挺有用。

mysql> select sid, sleep(1) from testdb.student;
+------+----------+
| sid  | sleep(1) |
+------+----------+
| 01   |        0 |
| 02   |        0 |
| 03   |        0 |
| 04   |        0 |
| 05   |        0 |
| 06   |        0 |
| 07   |        0 |
| 09   |        0 |
| 10   |        0 |
| 11   |        0 |
| 12   |        0 |
| 13   |        0 |
| 14   |        0 |
| 14   |        0 |
| 14   |        0 |
| 15   |        0 |
| 15   |        0 |
| 15   |        0 |
+------+----------+
18 rows in set (18.16 sec)


mysql> select sid, sleep(1) from testdb.student limit 1;
+------+----------+
| sid  | sleep(1) |
+------+----------+
| 01   |        0 |
+------+----------+
1 row in set (1.01 sec)

mysql> select sid, sleep(0.1) from testdb.student limit 1;
+------+------------+
| sid  | sleep(0.1) |
+------+------------+
| 01   |          0 |
+------+------------+
1 row in set (0.10 sec)

mysql> select sid, sleep(0) from testdb.student limit 1;
+------+----------+
| sid  | sleep(0) |
+------+----------+
| 01   |        0 |
+------+----------+
1 row in set (0.00 sec)

mysql> select *, sleep(null) from testdb.student limit 1;
ERROR 1210 (HY000): Incorrect arguments to sleep.

mysql> select *, sleep(-1) from testdb.student limit 1;
ERROR 1210 (HY000): Incorrect arguments to sleep.

6. mysqldump中关于–single-transaction选项

–single-transaction : Issue a BEGIN SQL statement before dumping data from server
这个选项设置事务隔离级别为Repeatable read,并且在导出数据之前发送start transaction命令。
目前只在InnoDB存储引擎相关表起作用,用于导出start transaction命令发起时间点的一致性数据,而不会阻塞其他会话。
一致性读与下列表操作不兼容:ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE。并且不能与–lock-tables选项一起使用,原因是LOCK TABLES操作有隐式commit。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值