做者:嶽明強
愛可生北京分公司 DBA 團隊成員,負責數據庫管理平臺的運維和 MySQL 問題處理。擅長對 MySQL 的故障定位。
本文來源:原創投稿
*愛可生開源社區出品,原創內容未經受權不得隨意使用,轉載請聯繫小編並註明來源。
有的時候 SQL 語句被鎖住了,但是經過 show processlist 找不到加鎖的的 SQL 語句,這個時候應該怎麼排查呢mysql
performance_schema = on;
一、建一個表,插入三條數據sql
mysql> use test1; Database changed mysql> create table action1(id int); Query OK, 0 rows affected (0.11 sec) mysql> insert into action1 values(1),(2),(3); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from action1; +------+ | id | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec)
二、開啓一個事務,刪除掉一行記錄,但不提交數據庫
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> delete from action1 where id = 3; Query OK, 1 row affected (0.00 sec)
三、另開啓一個事務,更新這條語句,會被鎖住運維
mysql> update action1 set id = 7 where id = 3;
四、經過 show processlist 只能看到一條正在執行的 SQL 語句測試
mysql> show processlist; | 22188 | root | localhost | test1 | Sleep | 483 | | NULL | | 22218 | root | localhost | NULL | Query | 0 | starting | show processlist | | 22226 | root | localhost | test1 | Query | 3 | updating | update action1 set id = 7 where id = 3 | +-------+-------------+--------------------+-------+---------+------+----------+----------------------------------------+
五、接下來就是咱們知道的,經過 information_schema 庫裏的 INNODBTRX、INNODBLOCKS 、INNODBLOCK_WAITS 得到的一個鎖信息spa
mysql> select * from INNODB_LOCK_WAITS; +-------------------+-------------------+-----------------+------------------+ | requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id | +-------------------+-------------------+-----------------+------------------+ | 5978292 | 5978292:542:3:2 | 5976374 | 5976374:542:3:2 | +-------------------+-------------------+-----------------+------------------+ 1 row in set, 1 warning (0.00 sec) mysql> select * from INNODB_LOCKs; +-----------------+-------------+-----------+-----------+-------------------+-----------------+------------+-----------+----------+----------------+ | lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data | +-----------------+-------------+-----------+-----------+-------------------+-----------------+------------+-----------+----------+----------------+ | 5978292:542:3:2 | 5978292 | X | RECORD | `test1`.`action1` | GEN_CLUST_INDEX | 542 | 3 | 2 | 0x00000029D504 | | 5976374:542:3:2 | 5976374 | X | RECORD | `test1`.`action1` | GEN_CLUST_INDEX | 542 | 3 | 2 | 0x00000029D504 | +-----------------+-------------+-----------+-----------+-------------------+-----------------+------------+-----------+----------+----------------+ 2 rows in set, 1 warning (0.00 sec) mysql> select trx_id,trx_started,trx_requested_lock_id,trx_query,trx_mysql_thread_id from INNODB_TRX; +---------+---------------------+-----------------------+----------------------------------------+---------------------+ | trx_id | trx_started | trx_requested_lock_id | trx_query | trx_mysql_thread_id | +---------+---------------------+-----------------------+----------------------------------------+---------------------+ | 5978292 | 2020-07-26 22:55:33 | 5978292:542:3:2 | update action1 set id = 7 where id = 3 | 22226 | | 5976374 | 2020-07-26 22:47:33 | NULL | NULL | 22188 | +---------+---------------------+-----------------------+----------------------------------------+---------------------+
六、從上面能夠看出來是 thread_id 爲 22188 的執行的 SQL 語句鎖住了後面的更新操做,可是咱們從上文中 show processlist 中並未看到這條事務,測試環境咱們能夠直接 kill 掉對應的線程號,但若是是生產環境中,咱們須要找到對應的 SQL 語句,根據相應的語句再考慮接下來應該怎麼處理線程
七、須要結合 performance_schema.threads 找到對應的事務號code
mysql> select * from performance_schema.threads where processlist_ID = 22188\G *************************** 1. row *************************** THREAD_ID: 22225 //perfoamance_schema中的事務計數器 NAME: thread/sql/one_connection TYPE: FOREGROUND PROCESSLIST_ID: 22188 //從show processlist中看到的id PROCESSLIST_USER: root PROCESSLIST_HOST: localhost PROCESSLIST_DB: test1 PROCESSLIST_COMMAND: Sleep PROCESSLIST_TIME: 1527 PROCESSLIST_STATE: NULL PROCESSLIST_INFO: NULL PARENT_THREAD_ID: NULL ROLE: NULL INSTRUMENTED: YES HISTORY: YES CONNECTION_TYPE: Socket THREAD_OS_ID:8632 1 row in set (0.00 sec)
八、找到事務號,能夠從 events_statements_current 找到對應的 SQL 語句:SQL_TEXTorm
mysql> select * from events_statements_current where THREAD_ID = 22225\G *************************** 1. row *************************** THREAD_ID: 22225 EVENT_ID: 14 END_EVENT_ID: 14 EVENT_NAME: statement/sql/delete SOURCE: TIMER_START: 546246699055725000 TIMER_END: 546246699593817000 TIMER_WAIT: 538092000 LOCK_TIME: 238000000 SQL_TEXT: delete from action1 where id = 3 //具體的sql語句 DIGEST: 8f9cdb489c76ec0e324f947cc3faaa7c DIGEST_TEXT: DELETE FROM `action1` WHERE `id` = ? CURRENT_SCHEMA: test1 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: 1 ROWS_SENT: 0 ROWS_EXAMINED: 3 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.00 sec)
九、能夠看到是一條 delete 阻塞了後續的 update,生產環境中能夠拿着這條 SQL 語句詢問開發,是否是有 kill 的必要。事務