您当前的位置:首页 > 计算机 > 软件应用 > 数据库 > MySQL

MySQL锁监控

时间:03-02来源:作者:点击数:

通常情况下,当出现锁问题时,我们习惯性通过 SHOW FULL PROCESSLIST 和 SHOW ENGINE INNODB STATUS 命令来判断事务中锁问题的情况。其实还有特别重要的三张表,即在 information_schema 数据库下的 innodb_trx、innodb_locks 和 innodb_lock_waits 表。 这三张表可以更方便地来帮助我们监控当前的事务并分析可能存在的锁问题。

下面通过实例来逐一了解一下这三张表。

例 1

在 A窗口中,开启一个事务,在查询 tb_student 表字段 age<15 的语句上加一个写锁,SQL 命令如下:

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test.tb_student WHERE age<15 FOE UPDATE;
+----+------+------+------+------+
| id | name | age  | sex  | num  |
+----+------+------+------+------+
|  3 | 王五 |   13 | 女   |   12 |
|  4 | 张四 |   13 | 女   |   12 |
|  6 | 赵六 |   12 | 女   |    4 |
+----+------+------+------+------+
3 rows in set (0.02 sec)

在 B窗口中开启一个事务,在 tb_student 表中插入 age=14 的记录,出现锁等待超时。

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO tb_student(name,age) VALUES ('dd',14);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

我们通过开始提到的三张表来分析出现的锁等待问题。

查询 innodb_trx 表,SQL 语句和运行结果如下:

mysql> SELECT * FROM information_schema.innodb_trx \G
*************************** 1. row ***************************
                    trx_id: 22694
                 trx_state: LOCK WAIT
               trx_started: 2019-08-25 09:17:26
     trx_requested_lock_id: 22694:197:3:1
          trx_wait_started: 2019-08-25 09:17:26
                trx_weight: 2
       trx_mysql_thread_id: 42
                 trx_query: INSERT INTO tb_student(name,age) VALUES ('dd',14)
       trx_operation_state: inserting
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 1136
           trx_rows_locked: 1
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 2. row ***************************
                    trx_id: 22693
                 trx_state: RUNNING
               trx_started: 2019-08-25 09:17:17
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 2
       trx_mysql_thread_id: 41
                 trx_query: select * FROM information_schema.innodb_trx
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 1136
           trx_rows_locked: 7
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
2 rows in set (0.01 sec)

以上各列含义说明如下:

列名 描述
trx_id 唯一的事务 id 号。本例为 22694 和 22693
trx_state 当前事务的状态。本例中 22694 事务号是 lock_wait 锁等待状态
trx_wait_started 事务开始等待的时间。本例为 2019-08-25 09:17:26
trx_mysql_thread_id 线程 id,与  SHOW FULL PROCESSLIST 相对应。本例为 42
trx_query 事务运行的 SQL 语句,本例为 INSERT INTO tb_student(name,age) VALUES ('dd',14)。
trx_operation_state 事务运行的状态。本例为 inserting。

使用 SHOW FULL PROCESSLIST 语句查看当前线程处理情况,通常用来处理突发事件,返回的结果是实时变化的。

mysql> SHOW FULL PROCESSLIST;
+----+------+-----------------+------+---------+------+----------+---------------------------------------------------+
| id | User | Host            | db   | Command | Time | State    | Info                                              |
+----+------+-----------------+------+---------+------+----------+---------------------------------------------------+
| 35 | root | localhost:64579 | test | Sleep   | 1772 |          | NULL                                              |
| 36 | root | localhost:64582 | NULL | Sleep   | 1775 |          | NULL                                              |
| 45 | root | localhost:64933 | test | Query   |    0 | starting | SHOW FULL PROCESSLIST                             |
| 46 | root | localhost:64934 | test | Query   |    8 | update   | INSERT INTO tb_student(name,age) VALUES ('dd',14) |
+----+------+-----------------+------+---------+------+----------+---------------------------------------------------+
4 rows in set (0.00 sec)

以上各列含义说明如下:

列名 描述
id 一个标识,kill 有问题的线程时使用
user 显示当前用户,如果不是 root,这个命令就只显示你权限范围内的 SQL 语句
host 显示这个语句是从哪个 ip 的哪个端口上发出的,可以用来追踪出问题语句的用户
db 显示这个进程目前连接的是哪个数据库
command 显示当前连接的执行命令,一般就是休眠(sleep),查询(query),连接(connect)
time 这个状态持续的时间,单位是秒
state 显示使用当前连接的 SQL 语句的状态
info 显示这个 SQL 语句,因为长度有限,所以长的 SQL 语句就会显示不全,是判断问题语句的重要依据

下面通过 innodb_lock_waits 和 innodb_locks 两张表来判断持有锁和锁等待的对象。本例中 22696 是锁等待的对象,22695 是持有锁的对象。

innodb_lock_waits 表包含每个被阻止 InnoDB 事务的一个或多个行,指示它已请求的锁以及阻止该请求的任何锁。

mysql> SELECT * FROM information_schema.innodb_lock_waits \G
*************************** 1. row ***************************
requesting_trx_id: 22696
requested_lock_id: 22696:197:3:1
  blocking_trx_id: 22695
blocking_lock_id: 22695:197:3:1
1 row in set, 1 warning (0.00 sec)

以上各列含义说明如下:

列名 描述
requesting_trx_id 请求(阻止)事务的 id
requested_lock_id 事务正在等待的锁的id
blocking_trx_id 阻止事务的 id
blocking_lock_id 阻止另一个事务继续进行的事务所持有的锁的 id

innodb_locks 表提供有关 InnoDB 事务已请求但尚未获取的每个锁的信息,以及事务持有的阻止另一个事务的锁。

mysql> SELECT * FROM information_schema.innodb_locks \G
*************************** 1. row ***************************
    lock_id: 22696:197:3:1
lock_trx_id: 22696
  lock_mode: X
  lock_type: RECORD
lock_table: `test`.`tb_student`
lock_index: PRIMARY
lock_space: 197
  lock_page: 3
   lock_pec: 1
  lock_data: supremum pseudo-record
*************************** 2. row ***************************
    lock_id: 22695:197:3:1
lock_trx_id: 22695
  lock_mode: X
  lock_type: RECORD
lock_table: `test`.`tb_student`
lock_index: PRIMARY
lock_space: 197
  lock_page: 3
   lock_pec: 1
  lock_data: supremum pseudo-record
2 rows in set, 1 warning (0.00 sec)

以上各列含义说明如下:

列名 描述
lock_id 一个唯一的锁 id 号,内部为 InnoDB
lock_trx_id 持有锁的交易的 id
lock_mode 如何请求锁定。允许锁定模式描述符 S,X, IS,IX, GAP,AUTO_INC 和 UNKNOWN。锁定模式描述符可以组合使用以识别特定的锁定模式。
lock_type 锁的类型
lock_table 已锁定或包含锁定记录的表的名称
lock_index 索引的名称,如果 lock_type 是 RECORD,否则 NULL
lock_space 锁定记录的表空间 id,如果 lock_type 是 RECORD,否则 NULL
lock_page 锁定记录的页码,如果 lock_type 是 RECORD,否则 NULL。
lock_pec 页面内锁定记录的堆号,如果 lock_type 是 RECORD,否则 NULL。
lock_data 与锁相关的数据。如果 lock_type 是 RECORD,是锁定的记录的主键值,否则 NULL。此列包含锁定行中主键列的值,格式为有效的 SQL 字符串。如果没有主键,lock_data 则是唯一的 InnoDB 内部行 id 号。如果对键值或范围高于索引中的最大值的间隙锁定,则 lock_data 报告 supremum pseudo-record。当包含锁定记录的页面不在缓冲池中时(如果在保持锁定时将其分页到磁盘),InnoDB不从磁盘获取页面,以避免不必要的磁盘操作。相反, lock_data 设置为 NULL。
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门