14.16.2.1 使用 InnoDB 事务和锁定信息

识别阻止的 Transaction

识别哪个 Transaction 会阻止另一个 Transaction 有时会很有帮助。包含有关InnoDB事务和数据锁的信息的 table 使您能够确定哪个事务正在 await 另一个事务以及正在请求哪个资源。 (有关这些 table 的说明,请参见第 14.16.2 节“ InnoDB INFORMATION_SCHEMA 事务和锁定信息”。)

假设三个会话正在同时运行。每个会话都对应一个 MySQL 线程,并依次执行一个事务。当这些会话发出以下语句,但尚未提交任何事务时,请考虑系统状态:

  • Session A:
BEGIN;
SELECT a FROM t FOR UPDATE;
SELECT SLEEP(100);
  • Session B:
SELECT b FROM t FOR UPDATE;
  • Session C:
SELECT c FROM t FOR UPDATE;

在这种情况下,使用以下查询来查看哪些事务正在 await,哪些事务正在阻止它们:

SELECT
  r.trx_id waiting_trx_id,
  r.trx_mysql_thread_id waiting_thread,
  r.trx_query waiting_query,
  b.trx_id blocking_trx_id,
  b.trx_mysql_thread_id blocking_thread,
  b.trx_query blocking_query
FROM       information_schema.innodb_lock_waits w
INNER JOIN information_schema.innodb_trx b
  ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.innodb_trx r
  ON r.trx_id = w.requesting_trx_id;

或者,更简单地说,使用sys模式innodb_lock_waits视图:

SELECT
  waiting_trx_id,
  waiting_pid,
  waiting_query,
  blocking_trx_id,
  blocking_pid,
  blocking_query
FROM sys.innodb_lock_waits;

如果为阻塞查询报告了 NULL 值,请参见在发布会话变为空闲之后识别阻塞查询

awaittrx IDwaiting threadwaiting query阻止 trx IDblocking threadblocking query
A46SELECT b FROM t FOR UPDATEA35SELECT SLEEP(100)
A57SELECT c FROM t FOR UPDATEA35SELECT SLEEP(100)
A57SELECT c FROM t FOR UPDATEA46SELECT b FROM t FOR UPDATE

在上 table 中,您可以通过“await 查询”或“阻止查询”列来标识会话。如你看到的:

  • 会话 B(trx id A4,线程6)和会话 C(trx id A5,线程7)都在 await 会话 A(trx id A3,线程5)。

  • 会话 C 正在 await 会话 B 和会话 A。

您可以在 tableINNODB_TRXINNODB_LOCKSINNODB_LOCK_WAITS中查看基础数据。

下 table 显示了INFORMATION_SCHEMA.INNODB_TRX的一些示例内容。

trx idtrx statetrx startedtrx 请求的锁定 IDtrxawait 开始trx weighttrx mysql 线程 IDtrx query
A3RUNNING2008-01-15 16:44:54NULLNULL25SELECT SLEEP(100)
A4LOCK WAIT2008-01-15 16:45:09A4:1:3:22008-01-15 16:45:0926SELECT b FROM t FOR UPDATE
A5LOCK WAIT2008-01-15 16:45:14A5:1:3:22008-01-15 16:45:1427SELECT c FROM t FOR UPDATE

下 table 显示了INFORMATION_SCHEMA.INNODB_LOCKS的一些示例内容。

lock id锁定 trx IDlock modelock typelock tablelock indexlock data
A3:1:3:2A3XRECORDtest.tPRIMARY0x0200
A4:1:3:2A4XRECORDtest.tPRIMARY0x0200
A5:1:3:2A5XRECORDtest.tPRIMARY0x0200

下 table 显示了INFORMATION_SCHEMA.INNODB_LOCK_WAITS的一些示例内容。

请求 trx ID请求的锁 ID阻止 trx ID阻止锁 ID
A4A4:1:3:2A3A3:1:3:2
A5A5:1:3:2A3A3:1:3:2
A5A5:1:3:2A4A4:1:3:2
在发布会话变为空闲之后识别阻塞查询

标识阻止事务时,如果发出查询的会话已变为空闲,则为阻止查询报告 NULL 值。在这种情况下,请使用以下步骤确定阻止查询:

  • 标识阻止事务的进程列 tableID。在sys.innodb_lock_waitstable 中,阻止事务的流程列 tableID 为blocking_pid值。

  • 使用blocking_pid,查询 MySQL Performance Schema threadstable,以确定阻塞事务的THREAD_ID。例如,如果blocking_pid为 6,则发出以下查询:

SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID = 6;
  • 使用THREAD_ID,查询 Performance Schema events_statements_currenttable,以确定该线程执行的最后一个查询。例如,如果THREAD_ID为 28,则发出以下查询:
SELECT THREAD_ID, SQL_TEXT FROM performance_schema.events_statements_current
WHERE THREAD_ID = 28\G
  • 如果线程执行的最后一个查询不足以确定锁定原因,则可以查询 Performance Schema events_statements_historytable 以查看线程执行的最后 10 条语句。
SELECT THREAD_ID, SQL_TEXT FROM performance_schema.events_statements_history
WHERE THREAD_ID = 28 ORDER BY EVENT_ID;
将 InnoDB 事务与 MySQL 会话相关联

有时,将内部InnoDB锁定信息与 MySQL 维护的会话级信息相关联很有用。例如,对于给定的InnoDB事务 ID,您可能想知道对应的 MySQL 会话 ID 和可能持有锁并因此阻止其他事务的会话的名称。

INFORMATION_SCHEMAtable 的以下输出取自某种程度上已加载的系统。可以看出,有几个事务正在运行。

以下INNODB_LOCKSINNODB_LOCK_WAITStable 显示:

  • 事务77F(正在执行INSERT)正在 await 事务77E77D77B提交。

  • 事务77E(正在执行INSERT)正在 await 事务77D77B提交。

  • 事务77D(正在执行INSERT)正在 await 事务77B提交。

  • 事务77B(正在执行INSERT)正在 await 事务77A提交。

  • 事务77A正在运行,当前正在执行SELECT

  • 事务E56(正在执行INSERT)正在 await 事务E55提交。

  • 事务E55(正在执行INSERT)正在 await 事务19C提交。

  • 事务19C正在运行,当前正在执行INSERT

Note

INFORMATION_SCHEMA PROCESSLISTINNODB_TRXtable 中显示的查询之间可能存在不一致。有关说明,请参见第 14.16.2.3 节“ InnoDB 事务和锁定信息的持久性和一致性”

下 table 显示了运行重workload的系统的INFORMATION_SCHEMA.PROCESSLIST的内容。

IDUSERHOSTDBCOMMANDTIMESTATEINFO
384rootlocalhosttestQuery10updateINSERT INTO t2 VALUES …
257rootlocalhosttestQuery3updateINSERT INTO t2 VALUES …
130rootlocalhosttestQuery0updateINSERT INTO t2 VALUES …
61rootlocalhosttestQuery1updateINSERT INTO t2 VALUES …
8rootlocalhosttestQuery1updateINSERT INTO t2 VALUES …
4rootlocalhosttestQuery0preparingSELECT * FROM PROCESSLIST
2rootlocalhosttestSleep566``NULL

下 table 显示了运行重workload的系统的INFORMATION_SCHEMA.INNODB_TRX的内容。

trx idtrx statetrx startedtrx 请求的锁定 IDtrxawait 开始trx weighttrx mysql 线程 IDtrx query
77FLOCK WAIT2008-01-15 13:10:1677F2008-01-15 13:10:161876INSERT INTO t09 (D, B, C) VALUES …
77ELOCK WAIT2008-01-15 13:10:1677E2008-01-15 13:10:161875INSERT INTO t09 (D, B, C) VALUES …
77DLOCK WAIT2008-01-15 13:10:1677D2008-01-15 13:10:161874INSERT INTO t09 (D, B, C) VALUES …
77BLOCK WAIT2008-01-15 13:10:1677B:733:12:12008-01-15 13:10:164873INSERT INTO t09 (D, B, C) VALUES …
77ARUNNING2008-01-15 13:10:16NULLNULL4872SELECT b, c FROM t09 WHERE …
E56LOCK WAIT2008-01-15 13:10:06E56:743:6:22008-01-15 13:10:065384INSERT INTO t2 VALUES …
E55LOCK WAIT2008-01-15 13:10:06E55:743:38:22008-01-15 13:10:13965257INSERT INTO t2 VALUES …
19CRUNNING2008-01-15 13:09:10NULLNULL2900130INSERT INTO t2 VALUES …
E15RUNNING2008-01-15 13:08:59NULLNULL539561INSERT INTO t2 VALUES …
51DRUNNING2008-01-15 13:08:47NULLNULL98078INSERT INTO t2 VALUES …

下 table 显示了运行重workload的系统的INFORMATION_SCHEMA.INNODB_LOCK_WAITS的内容。

请求 trx ID请求的锁 ID阻止 trx ID阻止锁 ID
77F77F:80677E77E:806
77F77F:80677D77D:806
77F77F:80677B77B:806
77E77E:80677D77D:806
77E77E:80677B77B:806
77D77D:80677B77B:806
77B77B:733:12:177A77A:733:12:1
E56E56:743:6:2E55E55:743:6:2
E55E55:743:38:219C19C:743:38:2

下 table 显示了运行重workload的系统的INFORMATION_SCHEMA.INNODB_LOCKS的内容。

lock id锁定 trx IDlock modelock typelock tablelock indexlock data
77F:80677FAUTO_INCTABLEtest.t09NULLNULL
77E:80677EAUTO_INCTABLEtest.t09NULLNULL
77D:80677DAUTO_INCTABLEtest.t09NULLNULL
77B:80677BAUTO_INCTABLEtest.t09NULLNULL
77B:733:12:177BXRECORDtest.t09PRIMARYsupremum pseudo-record
77A:733:12:177AXRECORDtest.t09PRIMARYsupremum pseudo-record
E56:743:6:2E56SRECORDtest.t2PRIMARY0, 0
E55:743:6:2E55XRECORDtest.t2PRIMARY0, 0
E55:743:38:2E55SRECORDtest.t2PRIMARY1922, 1922
19C:743:38:219CXRECORDtest.t2PRIMARY1922, 1922