#### 15.15.2.1 使用 InnoDB 事务和锁定信息

笔记

本节描述了 Performance Schema 公开的锁定信息[`数据锁`](performance-schema-data-locks-table.html)和[`data_lock_waits`](performance-schema-data-lock-waits-table.html)表，它取代了`INFORMATION_SCHEMA` `INNODB_LOCKS`和`INNODB_LOCK_WAITS`MySQL 8.0 中的表。对于用较旧的术语编写的类似讨论`INFORMATION_SCHEMA`表，见[使用 InnoDB 事务和锁定信息](https://dev.mysql.com/doc/refman/5.7/en/innodb-information-schema-examples.html)， 在[MySQL 5.7 参考手册](https://dev.mysql.com/doc/refman/5.7/en/).

##### 识别阻塞事务

有时识别哪个事务阻塞了另一个事务是有帮助的。包含有关信息的表`InnoDB`事务和数据锁使您能够确定哪个事务正在等待另一个事务，以及正在请求哪个资源。（有关这些表的说明，请参阅[第 15.15.2 节，“InnoDB 信息\_SCHEMA 交易和锁定信息”](innodb-information-schema-transactions.html).)

假设三个会话同时运行。每个会话对应一个 MySQL 线程，一个接一个地执行事务。考虑当这些会话发出以下语句但还没有提交其事务时系统的状态：

-   会议 A：

    ```
    BEGIN;
    SELECT a FROM t FOR UPDATE;
    SELECT SLEEP(100);
    ```

-   会话 B：

    ```
    SELECT b FROM t FOR UPDATE;
    ```

-   会议 C：

    ```
    SELECT c FROM t FOR UPDATE;
    ```

    在这种情况下，使用以下查询来查看哪些事务正在等待以及哪些事务正在阻塞它们：


```
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       performance_schema.data_lock_waits w
INNER JOIN information_schema.innodb_trx b
  ON b.trx_id = w.blocking_engine_transaction_id
INNER JOIN information_schema.innodb_trx r
  ON r.trx_id = w.requesting_engine_transaction_id;
```

或者，更简单地说，使用`系统`图式[`innodb_lock_waits`](sys-innodb-lock-waits.html)看法：

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

如果为阻塞查询报告 NULL 值，请参阅[在发出会话变为空闲后识别阻塞查询](innodb-information-schema-examples.html#innodb-information-schema-examples-null-blocking-query).

| 等待 trx id | 等待线程 | 等待查询 | 阻止 trx id | 阻塞线程 | 阻塞查询 |
| --------- | ---- | ---- | --------- | ---- | ---- |
| `A4` | `6` | `从 t 中选择 b 进行更新` | `A3` | `5` | `选择睡眠（100）` |
| `A5` | `7` | `从 t 中选择 c 进行更新` | `A3` | `5` | `选择睡眠（100）` |
| `A5` | `7` | `从 t 中选择 c 进行更新` | `A4` | `6` | `从 t 中选择 b 进行更新` |

在上表中，您可以通过“等待查询”或“阻塞查询”列来识别会话。如你看到的：

-   会话 B (trx id`A4`， 线`6`) 和会话 C (trx id`A5`， 线`7`) 都在等待会话 A (trx id`A3`， 线`5`）。

-   会话 C 正在等待会话 B 以及会话 A。

    您可以在`INFORMATION_SCHEMA` [`INNODB_TRX`](information-schema-innodb-trx-table.html)表和性能模式[`数据锁`](performance-schema-data-locks-table.html)和[`data_lock_waits`](performance-schema-data-lock-waits-table.html)表。

    下表显示了部分示例内容[`INNODB_TRX`](information-schema-innodb-trx-table.html)桌子。

[](<>)

| 交易编号 | 状态 | trx 开始 | trx 请求的锁 id | trx 等待开始 | 重量 | trx mysql线程id | trx 查询 |
| ---- | --- | ------ | ----------- | -------- | --- | ------------- | ------ |
| `A3` | `正在运行` | `2008-01-15 16:44:54` | `空值` | `空值` | `2` | `5` | `选择睡眠（100）` |
| `A4` | `锁定等待` | `2008-01-15 16:45:09` | `A4:1:3:2` | `2008-01-15 16:45:09` | `2` | `6` | `从 t 中选择 b 进行更新` |
| `A5` | `锁定等待` | `2008-01-15 16:45:14` | `A5:1:3:2` | `2008-01-15 16:45:14` | `2` | `7` | `从 t 中选择 c 进行更新` |

下表显示了部分示例内容[`数据锁`](performance-schema-data-locks-table.html)桌子。

[](<>)

| 锁ID | 锁定 trx id | 锁定模式 | 锁型 | 锁模式 | 锁表 | 锁定索引 | 锁定数据 |
| --- | --------- | ---- | --- | --- | --- | ---- | ---- |
| `A3:1:3:2` | `A3` | `X` | `记录` | `测试` | `吨` | `基本的` | `0x0200` |
| `A4:1:3:2` | `A4` | `X` | `记录` | `测试` | `吨` | `基本的` | `0x0200` |
| `A5:1:3:2` | `A5` | `X` | `记录` | `测试` | `吨` | `基本的` | `0x0200` |

下表显示了部分示例内容[`data_lock_waits`](performance-schema-data-lock-waits-table.html)桌子。

[](<>)

| 请求 trx id | 请求的锁 ID | 阻止 trx id | 阻塞锁ID |
| --------- | ------- | --------- | ----- |
| `A4` | `A4:1:3:2` | `A3` | `A3:1:3:2` |
| `A5` | `A5:1:3:2` | `A3` | `A3:1:3:2` |
| `A5` | `A5:1:3:2` | `A4` | `A4:1:3:2` |

##### 在发出会话变为空闲后识别阻塞查询

识别阻塞事务时，如果发出查询的会话已空闲，则为阻塞查询报告 NULL 值。在这种情况下，请使用以下步骤来确定阻塞查询：

1.  识别阻塞事务的进程列表 ID。在里面[`sys.innodb_lock_waits`](sys-innodb-lock-waits.html)表中，阻塞事务的进程列表 ID 是`阻塞_pid`价值。

2.  使用`阻塞_pid`，查询MySQL Performance Schema[`线程`](performance-schema-threads-table.html)表来确定`THREAD_ID`的阻塞事务。例如，如果`阻塞_pid`是 6，发出这个查询：

    ```
    SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID = 6;
    ```

3.  使用`THREAD_ID`，查询Performance Schema[`events_statements_current`](performance-schema-events-statements-current-table.html)表来确定线程执行的最后一个查询。例如，如果`THREAD_ID`是 28，发出这个查询：

    ```
    SELECT THREAD_ID, SQL_TEXT FROM performance_schema.events_statements_current
    WHERE THREAD_ID = 28\G
    ```

4.  如果线程执行的最后一个查询没有足够的信息来确定持有锁的原因，可以查询 Performance Schema[`events_statements_history`](performance-schema-events-statements-history-table.html)table 查看线程执行的最后 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_SCHEMA` [`INNODB_TRX`](information-schema-innodb-trx-table.html)表和性能模式[`数据锁`](performance-schema-data-locks-table.html)和[`data_lock_waits`](performance-schema-data-lock-waits-table.html)表是从一个有些负载的系统中获取的。可以看出，有几个事务正在运行。

下列[`数据锁`](performance-schema-data-locks-table.html)和[`data_lock_waits`](performance-schema-data-lock-waits-table.html)表格显示：

-   交易`77F`（执行一个[`插入`](insert.html)) 正在等待交易`77E`,`77D`， 和`77B`承诺。

-   交易`77E`（执行一个[`插入`](insert.html)) 正在等待交易`77D`和`77B`承诺。

-   交易`77D`（执行一个[`插入`](insert.html)) 正在等待交易`77B`承诺。

-   交易`77B`（执行一个[`插入`](insert.html)) 正在等待交易`77A`承诺。

-   交易`77A`正在运行，当前正在执行[`选择`](select.html).

-   交易`E56`（执行一个[`插入`](insert.html)) 正在等待交易`E55`承诺。

-   交易`E55`（执行一个[`插入`](insert.html)) 正在等待交易`19C`承诺。

-   交易`19C`正在运行，当前正在执行[`插入`](insert.html).

笔记

显示的查询之间可能存在不一致`INFORMATION_SCHEMA` [`进程列表`](information-schema-processlist-table.html)和[`INNODB_TRX`](information-schema-innodb-trx-table.html)表。有关说明，请参阅[第 15.15.2.3 节，“InnoDB 事务和锁定信息的持久性和一致性”](innodb-information-schema-internal-data.html).

下表显示了内容[`进程列表`](information-schema-processlist-table.html)运行繁重的系统的表[工作量](glossary.html#glos_workload).

[](<>)

| ID | 用户 | 主持人 | D B | 命令 | 时间 | 状态 | 信息 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `384` | `根` | `本地主机` | `测试` | `询问` | `10` | `更新` | `插入 t2 值……` |
| `257` | `根` | `本地主机` | `测试` | `询问` | `3` | `更新` | `插入 t2 值……` |
| `130` | `根` | `本地主机` | `测试` | `询问` | `0` | `更新` | `插入 t2 值……` |
| `61` | `根` | `本地主机` | `测试` | `询问` | `1` | `更新` | `插入 t2 值……` |
| `8` | `根` | `本地主机` | `测试` | `询问` | `1` | `更新` | `插入 t2 值……` |
| `4` | `根` | `本地主机` | `测试` | `询问` | `0` | `准备` | `从进程列表中选择 *` |
| `2` | `根` | `本地主机` | `测试` | `睡觉` | `566` | ``     \|          `空值` |  |

下表显示了内容[`INNODB_TRX`](information-schema-innodb-trx-table.html)运行繁重的系统的表[工作量](glossary.html#glos_workload).

[](<>)

| 交易编号 | 状态 | trx 开始 | trx 请求的锁 id | trx 等待开始 | 重量 | trx mysql线程id | trx 查询 |
| ---- | --- | ------ | ----------- | -------- | --- | ------------- | ------ |
| `77F` | `锁定等待` | `2008-01-15 13:10:16` | `77F` | `2008-01-15 13:10:16` | `1` | `876` | `插入 t09 (D, B, C) 值……` |
| `77E` | `锁定等待` | `2008-01-15 13:10:16` | `77E` | `2008-01-15 13:10:16` | `1` | `875` | `插入 t09 (D, B, C) 值……` |
| `77D` | `锁定等待` | `2008-01-15 13:10:16` | `77D` | `2008-01-15 13:10:16` | `1` | `874` | `插入 t09 (D, B, C) 值……` |
| `77B` | `锁定等待` | `2008-01-15 13:10:16` | `77B:733:12:1` | `2008-01-15 13:10:16` | `4` | `873` | `插入 t09 (D, B, C) 值……` |
| `77A` | `正在运行` | `2008-01-15 13:10:16` | `空值` | `空值` | `4` | `872` | `从 t09 选择 b、c 在哪里……` |
| `E56` | `锁定等待` | `2008-01-15 13:10:06` | `E56:743:6:2` | `2008-01-15 13:10:06` | `5` | `384` | `插入 t2 值……` |
| `E55` | `锁定等待` | `2008-01-15 13:10:06` | `E55:743:38:2` | `2008-01-15 13:10:13` | `965` | `257` | `插入 t2 值……` |
| `19C` | `正在运行` | `2008-01-15 13:09:10` | `空值` | `空值` | `2900` | `130` | `插入 t2 值……` |
| `E15` | `正在运行` | `2008-01-15 13:08:59` | `空值` | `空值` | `5395` | `61` | `插入 t2 值……` |
| `51D` | `正在运行` | `2008-01-15 13:08:47` | `空值` | `空值` | `9807` | `8` | `插入 t2 值……` |

下表显示了内容[`data_lock_waits`](performance-schema-data-lock-waits-table.html)运行繁重的系统的表[工作量](glossary.html#glos_workload).

[](<>)

| 请求 trx id | 请求的锁 ID | 阻止 trx id | 阻塞锁ID |
| --------- | ------- | --------- | ----- |
| `77F` | `77F:806` | `77E` | `77E:806` |
| `77F` | `77F:806` | `77D` | `77D:806` |
| `77F` | `77F:806` | `77B` | `77B:806` |
| `77E` | `77E:806` | `77D` | `77D:806` |
| `77E` | `77E:806` | `77B` | `77B:806` |
| `77D` | `77D:806` | `77B` | `77B:806` |
| `77B` | `77B:733:12:1` | `77A` | `77A:733:12:1` |
| `E56` | `E56:743:6:2` | `E55` | `E55:743:6:2` |
| `E55` | `E55:743:38:2` | `19C` | `19C:743:38:2` |

下表显示了内容[`数据锁`](performance-schema-data-locks-table.html)运行繁重的系统的表[工作量](glossary.html#glos_workload).

[](<>)

| 锁ID | 锁定 trx id | 锁定模式 | 锁型 | 锁模式 | 锁表 | 锁定索引 | 锁定数据 |
| --- | --------- | ---- | --- | --- | --- | ---- | ---- |
| `77F:806` | `77F` | `AUTO_INC` | `桌子` | `测试` | `t09` | `空值` | `空值` |
| `77E:806` | `77E` | `AUTO_INC` | `桌子` | `测试` | `t09` | `空值` | `空值` |
| `77D:806` | `77D` | `AUTO_INC` | `桌子` | `测试` | `t09` | `空值` | `空值` |
| `77B:806` | `77B` | `AUTO_INC` | `桌子` | `测试` | `t09` | `空值` | `空值` |
| `77B:733:12:1` | `77B` | `X` | `记录` | `测试` | `t09` | `基本的` | `最高伪记录` |
| `77A:733:12:1` | `77A` | `X` | `记录` | `测试` | `t09` | `基本的` | `最高伪记录` |
| `E56:743:6:2` | `E56` | `小号` | `记录` | `测试` | `t2` | `基本的` | `0, 0` |
| `E55:743:6:2` | `E55` | `X` | `记录` | `测试` | `t2` | `基本的` | `0, 0` |
| `E55:743:38:2` | `E55` | `小号` | `记录` | `测试` | `t2` | `基本的` | `1922, 1922` |
| `19C:743:38:2` | `19C` | `X` | `记录` | `测试` | `t2` | `基本的` | `1922, 1922` |
