测试环境
centos7.4+mysql5.7.29
启用 performance_schema
mysql> show variables like ‘%performance%’
±---------------------------------------------------------±------+
| Variable_name | Value |
±---------------------------------------------------------±------+
| performance_schema | ON
说明:默认情况下performance_schema 在5.7下是启用的,这里最好对setup_instruments采集器配置项和setup_consumers表中的配置项进行启用
mysql> update setup_instruments set enabled=‘YES’,TIMED=‘YES’ where name like ‘%wait%’;
Query OK, 316 rows affected (0.01 sec)
Rows matched: 370 Changed: 316 Warnings: 0
mysql> desc setup_consumers;
±--------±-----------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±--------±-----------------±-----±----±--------±------+
| NAME | varchar(64) | NO | | NULL | |
| ENABLED | enum(‘YES’,‘NO’) | NO | | NULL | |
±--------±-----------------±-----±----±--------±------+
mysql> update setup_consumers set enabled=‘YES’ where name like ‘%wait%’;
Query OK, 3 rows affected (0.00 sec)
mysql> select * from setup_consumers where name like ‘%wait%’ ;
±--------------------------±--------+
| NAME | ENABLED |
±--------------------------±--------+
| events_waits_current | YES |
| events_waits_history | YES |
| events_waits_history_long | YES |
±--------------------------±--------+
测试场景
1、通过一个会话对表执行 lock table操作
2、通过另一个会话对该进行更新
3、查看哪个会话持有表级锁
mysql> lock table aa read;
mysql> select connection_id();
±----------------+
| connection_id() |
±----------------+
| 7 |
会话2
mysql> select connection_id();
±----------------+
| connection_id() |
±----------------+
| 5 |
mysql> update aa set col3=4 where col1>800;
解决思路与方法
1、通过show processlist查看表锁信息
mysql> show processlist;
+----+-----------------+-----------+--------------------+---------+------+---------------------------------+-------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-----------------+-----------+--------------------+---------+------+---------------------------------+-------------------------------------+
| 1 | event_scheduler | localhost | NULL | Daemon | 2938 | Waiting on empty queue | NULL |
| 5 | root | localhost | test | Query | 497 | Waiting for table metadata lock | update aa set col3=4 where col1>900 |
| 6 | root | localhost | performance_schema | Query | 0 | starting | show processlist |
| 7 | root | localhost | test | Sleep | 510 | | NULL |
+----+-----------------+-----------+--------------------+---------+------+---------------------------------+-------------------------------------+
测试环境只有几条记录,所以很容易就是知道是哪个会话持有了表级锁,这里应该是会话7,但在生产环境中就不一定了,
2、通过查询事务无法获取到server层面相应信息,
mysql> select * from information_schema.innodb_trx;
mysql> select * from information_schema.innodb_locks;
mysql> select * from information_schema.innodb_lock_waits;
mysql> select * from performance_schema.metadata_locks \G;
Empty set (0.00 sec)
ERROR:
No query specified
这里没有信息输出是因为没有开启setup_instruments和setup_consumers相应的参数导致的
3、查询metadata_locks 信息
select * from performance_schema.metadata_locks where owner_thread_id !=sys.ps_thread_id(connection_id()) \G
*************************** 1. row ***************************
OBJECT_TYPE: TABLE
OBJECT_SCHEMA: test
OBJECT_NAME: aa
OBJECT_INSTANCE_BEGIN: 139975879812688
LOCK_TYPE: SHARED_READ_ONLY
LOCK_DURATION: TRANSACTION
LOCK_STATUS: GRANTED
SOURCE:
OWNER_THREAD_ID: 32
OWNER_EVENT_ID: 418
*************************** 2. row ***************************
OBJECT_TYPE: GLOBAL
OBJECT_SCHEMA: NULL
OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139975668677024
LOCK_TYPE: INTENTION_EXCLUSIVE
LOCK_DURATION: STATEMENT
LOCK_STATUS: GRANTED
SOURCE:
OWNER_THREAD_ID: 30
OWNER_EVENT_ID: 36
*************************** 3. row ***************************
OBJECT_TYPE: TABLE
OBJECT_SCHEMA: test
OBJECT_NAME: aa
OBJECT_INSTANCE_BEGIN: 139975668591216
LOCK_TYPE: SHARED_WRITE
LOCK_DURATION: TRANSACTION
LOCK_STATUS: PENDING
SOURCE:
OWNER_THREAD_ID: 30
OWNER_EVENT_ID: 36
3 rows in set (0.10 sec)
说明:在metadata_locks中能看到元数据锁类型、表信息,但无法看到相应的SQL语句
4、通过table_handles查看表中的锁
mysql> select * from performance_schema.table_handles;
+-------------+---------------+-------------+-----------------------+-----------------+----------------+---------------+---------------+
| OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | OBJECT_INSTANCE_BEGIN | OWNER_THREAD_ID | OWNER_EVENT_ID | INTERNAL_LOCK | EXTERNAL_LOCK |
+-------------+---------------+-------------+-----------------------+-----------------+----------------+---------------+---------------+
| TABLE | test | Sheet1 | 139975869924496 | 0 | 0 | NULL | NULL |
| TABLE | test | aa | 139975869990688 | 0 | 0 | NULL | NULL |
| TABLE | test | bb | 139975870002256 | 0 | 0 | NULL | NULL |
*******************************
| TABLE | test | yjgk | 139975668759360 | 0 | 0 | NULL | NULL |
| TABLE | test | Sheet1 | 139975870007520 | 0 | 0 | NULL | NULL |
| TABLE | test | aa | 139975869907936 | 32 | 420 | NULL | READ EXTERNAL |
| TABLE | test | bb | 139975869914368 | 0 | 0 | NULL | NULL |
***************
| TABLE | test | user | 139975879937840 | 0 | 0 | NULL | NULL |
| TABLE | test | yjgk | 139975879947648 | 0 | 0 | NULL | NULL |
+-------------+---------------+-------------+-----------------------+-----------------+----------------+---------------+--------------
5、查看events_statements_current 执行的SQL语句
mysql> select * from performance_schema.events_statements_current \G;
*************************** 1. row ***************************
THREAD_ID: 30
EVENT_ID: 30
END_EVENT_ID: NULL
EVENT_NAME: statement/sql/update
SOURCE:
TIMER_START: 2451892308210000
TIMER_END: 2856840026831000
TIMER_WAIT: 404947718621000
LOCK_TIME: 0
SQL_TEXT: update aa set col3=4 where col1>900
DIGEST: NULL
DIGEST_TEXT: NULL
CURRENT_SCHEMA: test
OBJECT_TYPE: NULL
OBJECT_SCHEMA: NULL
OBJECT_NAME: NULL OBJECT_INSTANCE_BEGIN: NULL
MYSQL_ERRNO: 0
RETURNED_SQLSTATE: NULL
MESSAGE_TEXT: NULL
ERRORS: 0
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
*************************** 2. row ***************************
THREAD_ID: 31
EVENT_ID: 457
END_EVENT_ID: NULL
EVENT_NAME: statement/sql/select
SOURCE:
TIMER_START: 2856839656572000
TIMER_END: 2856840058364000
TIMER_WAIT: 401792000
LOCK_TIME: 230000000
SQL_TEXT: select * from performance_schema.events_statements_current
DIGEST: NULL
DIGEST_TEXT: NULL
CURRENT_SCHEMA: performance_schema
OBJECT_TYPE: NULL
OBJECT_SCHEMA: NULL
OBJECT_NAME: NULL OBJECT_INSTANCE_BEGIN: NULL
MYSQL_ERRNO: 0
RETURNED_SQLSTATE: NULL
MESSAGE_TEXT: NULL
ERRORS: 0 ………………………………………………………………………………
NO_GOOD_INDEX_USED: 0
NESTING_EVENT_ID: NULL
NESTING_EVENT_TYPE: NULL
NESTING_EVENT_LEVEL: 0
*************************** 3. row ***************************
THREAD_ID: 32
EVENT_ID: 412
END_EVENT_ID: 429
EVENT_NAME: statement/sql/lock_tables
SOURCE:
TIMER_START: 2438691100503000
TIMER_END: 2438691297187000
TIMER_WAIT: 196684000
LOCK_TIME: 123000000
SQL_TEXT: lock table aa read
DIGEST: 0c4323e259b6706bec0bcc2870e4c3c8
DIGEST_TEXT: LOCK TABLEaa
READ
CURRENT_SCHEMA: test
OBJECT_TYPE: NULL
OBJECT_SCHEMA: NULL
OBJECT_NAME: NULL OBJECT_INSTANCE_BEGIN: NULL
MYSQL_ERRNO: 0
RETURNED_SQLSTATE: 00000
MESSAGE_TEXT: NULL
ERRORS: 0
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 3 rows in set (0.01 sec)ERROR: No query specified
说明:这里就能看到那个thread_id执行了什么SQL语句,根据thread_id查看processlist_id
mysql> select processlist_id from performance_schema.threads where thread_id=32;
±---------------+
| processlist_id |
±---------------+
| 7 |
±---------------+
1 row in set (0.00 sec)
mysql> show processlist;
+----+-----------------+-----------+--------------------+---------+------+---------------------------------+-------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-----------------+-----------+--------------------+---------+------+---------------------------------+-------------------------------------+
| 1 | event_scheduler | localhost | NULL | Daemon | 2938 | Waiting on empty queue | NULL |
| 5 | root | localhost | test | Query | 497 | Waiting for table metadata lock | update aa set col3=4 where col1>900 |
| 6 | root | localhost | performance_schema | Query | 0 | starting | show processlist |
| 7 | root | localhost | test | Sleep | 510 | | NULL |
+----+-----------------+-----------+--------------------+---------+------+---------------------------------+-------------------------------------+
4 rows in set (0.00 sec)
6、与研发人员确认相应的SQL后,kill掉相应的线程ID即可
mysql> kill 7;
Query OK, 0 rows affected (0.00 sec)
mysql> show processlist;
+----+-----------------+-----------+--------------------+---------+------+------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-----------------+-----------+--------------------+---------+------+------------------------+------------------+
| 1 | event_scheduler | localhost | NULL | Daemon | 2953 | Waiting on empty queue | NULL |
| 5 | root | localhost | test | Sleep | 512 | | NULL |
| 6 | root | localhost | performance_schema | Query | 0 | starting | show processlist |
+----+-----------------+-----------+--------------------+---------+------+------------------------+------------------+
3 rows in set (0.00 sec)
总结
1、通过show processlist方式无法直接了解到是那个会话持有表级锁
2、通过metadata_locks 可以了解到元数据锁的相关信息和表信息
3、通过table_handles可以查询到表上具体的信息
4、通过events_statements_current根据时间先后可以知道每 个线程当前执行的SQL语句
5、根据events_statements_current中的thread_id在threads中能查询具体的线程ID,这就与show processlist中process_id相应起来。