回城传送–》《32天SQL筑基》
今天是学习 SQL 打卡的第 25 天,每天我会提供一篇文章供群成员阅读( 不需要订阅付钱 )。
希望大家先自己思考,如果实在没有想法,再看下面的解题思路,自己再实现一遍。在小虚竹JAVA社区 中对应的 【打卡贴】打卡,今天的任务就算完成了,养成每天学习打卡的好习惯。
虚竹哥会组织大家一起学习同一篇文章,所以有什么问题都可以在群里问,群里的小伙伴可以迅速地帮到你,一个人可以走得很快,一群人可以走得很远,有一起学习交流的战友,是多么幸运的事情。
我的学习策略很简单,题海策略+ 费曼学习法。如果能把这些题都认认真真自己实现一遍,那意味着 SQL 已经筑基成功了。后面的进阶学习,可以继续跟着我,一起走向架构师之路。
今天的学习内容是:SQL进阶-查询优化- performance_schema系列实战二:锁问题排查(全局读锁)
全局锁是对整个数据库来说的,当对数据库加了全局读锁,任何请求都不能对数据库进行加写锁操作了;当对数据库加了全局写锁,后面对数据库的加读锁和写锁操作会被阻塞。
全局锁适合在进行主从备份数据、或者导入导出数据的时候才会对全局进行加锁。
在MySQL 5.7之前的版本,要排查谁持有全局读锁通常在数据库层面是很难直接查询到有用数据(innodb_locks表也只能记录innodb层的锁信息,而全局读锁是server层的锁,所以也无法查询到)。
从MySQL 5.7开始提供表performance_schema.metadata_locks表记录一些Server层的锁信息(包括全局读锁和MDL锁等),下面我们通过一个示例来演示然后使用performance_schema来找出谁持有全局读锁。
使用sysbench准备初始化数据
创建测试数据库sysbenchdemo
create database sysbenchdemo;
准备测试数据:
sysbench /usr/share/sysbench/oltp_insert.lua \
--mysql-host=localhost \
--mysql-port=3306 \
--mysql-socket=/tmp/mysql.sock \
--mysql-user=root \
--mysql-password=xiaoxuzhu \
--mysql-db=sysbenchdemo \
--db-driver=mysql \
--tables=8 \
--table-size=100000 \
--time=180 prepare
登录mysql数据库
use sysbenchdemo;
flush table with read lock;
查询以下加锁线程的process id,以便后续排查过程好对应
select connection_id();
登录mysql数据库
use sysbenchdemo;
select * from sbtest1 limit 1;
select connection_id();
修改sbtest1表的第一条数据
update sbtest1 set pad='xxx' where id=1;
我们还可以通过performance_schema.metadata_locks表来排查谁持有全局读锁,全局读锁通常在该表记录着同一个会话的OBJECT_TYPE为global和commit、LOCK_TYPE都为SHARED的两把显式锁
select * from performance_schema.metadata_locks where OWNER_THREAD_ID!=sys.ps_thread_id(connection_id());
其中OWNER_THREAD_ID: # 持有锁的内部线程ID
查看process id为 12372,12427 各自对应的内部线程ID是多少
select sys.ps_thread_id(12372);
process id=12372的线程对应的内部线程ID正好为12536,说明就是process id=12372的线程持有了全局读锁
select sys.ps_thread_id(12427);
proces id=12427的线程对应的内部线程正好是12591,说明在等待全局读锁的就是process id=12427的线程
结合上面的分析,再通过 show processlist找到对应行记录信息,就可大概推测出这是哪个的业务语句。
在产生阻塞的会话内释放全局读锁。
unlock tables;
通过本文学习,学会了什么是全局锁以及全局锁的适用场景,通过实战演练排查全局读锁问题,从理论到实战的介绍,可以加深对全局锁的理解。
应用示例荟萃 | performance_schema全方位介绍(上)
我是虚竹哥,我们明天见~