## 模块 3：监控潜在的 Runaway Query

+ 从模块 2 我们知道，识别一个 Runaway Query 需要一定时间。例如，如果设置 `EXEC_ELAPSED='10s'`，那么每个 Runaway Query 至少需要 10 秒才能被识别。过多尚未被识别的 Runaway Query 可能会耗尽系统资源。
+ 通过使用 `WATCH` 功能，TiDB 能够在查询开始执行前就识别出 Runaway Query 。
+ `WATCH` 功能的选项包括 `EXACT`（精确匹配）、`SIMILAR`（匹配 SQL digest）、`PLAN`（匹配执行计划 digest）。

### 步骤 1. 重新定义资源组

+ 在下面的 SQL 中，我们重新定义了资源组。与模块 2 的资源组相比，这里新增了 `WATCH=SIMILAR` 和 `DURATION='100m'`。这意味着，一旦某个查询被识别为 Runaway Query ，所有与其 SQL digest 相同的查询在 100 分钟内都会被直接判定为 Runaway Query 并被拦截，不会被执行。

  ```sql
  ALTER RESOURCE GROUP rg1 QUERY_LIMIT=(PROCESSED_KEYS=100, ACTION=KILL, WATCH=SIMILAR DURATION='100m');
  ```

  ```sql
  SET RESOURCE GROUP `rg1`;
  SELECT CURRENT_RESOURCE_GROUP();
  ```

  ```output
  tidb:db1> SET RESOURCE GROUP `rg1`;
  Query OK, 0 rows affected (0.00 sec)

  tidb:db1> SELECT CURRENT_RESOURCE_GROUP();
  +--------------------------+
  | CURRENT_RESOURCE_GROUP() |
  +--------------------------+
  | rg1                      |
  +--------------------------+
  1 row in set (0.00 sec)
  ```

### 步骤 2. 生成一些查询

  ```sql
  USE sbtest;
  SELECT
    CONCAT(
      'UPDATE sbtest1 SET k = ',
      k,
      ' WHERE c = ''',
      c,
      ''';'
    ) AS update_stmt
  FROM sbtest1
  WHERE id IN (1123127, 3852438, 5964556, 9475339);
  ```

  ```output
  +---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | update_stmt                                                                                                                                                         |
  +---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  | UPDATE sbtest1 SET k = 5017151 WHERE c = '84493442613-55715520812-07466942581-87906122717-51164395568-98852954940-85704352045-80573166498-09592001496-94838080154'; |
  | UPDATE sbtest1 SET k = 4473488 WHERE c = '16343179582-65765105184-12762861962-64885861338-91163734747-54197012107-93125617766-13310713443-81881465217-52031359817'; |
  | UPDATE sbtest1 SET k = 5018359 WHERE c = '30686701254-95654597113-74779030530-51744141684-25702975952-73545252771-00587103499-70903471471-10016980123-39589338114'; |
  | UPDATE sbtest1 SET k = 4978938 WHERE c = '91059747631-65344828194-11158241479-43561595237-60087824823-10114555067-54188804463-85679024352-56990670474-10055950458'; |
  +---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  4 rows in set (0.00 sec)
  ```

### 步骤 3. 执行查询

+ 让我们执行第 2 步输出结果中的**第一条查询语句**。
+ 本步骤中，我们执行一个查询，由于处理了 1095654 个键，该查询会被判定为 Runaway Query 。
+ 注意，这次查询会实际执行，然后被终止。在 100 分钟的时间窗口内，所有 SQL digest 相同的后续查询都会被直接判定为 Runaway Query，不会被执行。

  ```output
  ERROR 8253 (HY000): Query execution was interrupted, identified as runaway query [ProcessedKeys = 1095654(100)]
  ```

### 步骤 4. 执行相似模式的查询

+ 本步骤中，我们执行一个与上一步类似的查询，只是 `c` 的值改成了 `abc0`。表中应该没有该记录。
+ 执行结果显示：`Quarantined and interrupted because of being in runaway watch list`。该查询与上一步的 SQL digest 相同，因此被直接拦截，没有被执行。

  ```sql
  UPDATE sbtest1 SET k = 4751268 WHERE c = 'abc0';
  ```

  ```output
  ERROR 8254 (HY000): Quarantined and interrupted because of being in runaway watch list
  ```

### 步骤 5. 查看 Runaway Query 监控列表

+ 下面的命令可以列出当前的监控（watch）列表。
+ 结果显示，在资源组 `rg1` 中，所有 SQL digest 为 `a7a2fbb8a227456777fd6d3dd68dee4089cb05413ccac0f3731d2fa538a09dea` 的查询会在 `2025-07-15 01:13:54` 到 `2025-07-15 02:53:54` 这个时间窗口内被拦截并终止。

  ```sql
  SELECT * from information_schema.runaway_watches ORDER BY id\G
  ```

  ```output
  tidb:db1> SELECT * from information_schema.runaway_watches ORDER BY id\G
  *************************** 1. row ***************************
                   ID: 1
  RESOURCE_GROUP_NAME: rg1
           START_TIME: 2025-07-15 01:13:54
             END_TIME: 2025-07-15 02:53:54
                WATCH: Similar
           WATCH_TEXT: a7a2fbb8a227456777fd6d3dd68dee4089cb05413ccac0f3731d2fa538a09dea
               SOURCE: 10.90.2.141:4000
               ACTION: Kill
                 RULE: ProcessedKeys = 1095654(100)
  ```

### 步骤 6. 手动添加监控（WATCH）规则

+ 有时你需要手动将某些查询加入监控列表。例如，`SELECT *` 这类查询对系统危害较大。

  ```sql
  QUERY WATCH ADD RESOURCE GROUP rg1 ACTION KILL SQL TEXT SIMILAR TO 'select * from sbtest1';
  ```

  ```output
  tidb:db1> QUERY WATCH ADD RESOURCE GROUP rg1 ACTION KILL SQL TEXT SIMILAR TO 'select * from sbtest1';
  +----------+
  | WATCH_ID |
  +----------+
  |        2 |
  +----------+
  1 row in set (0.00 sec)
  ```

### 步骤 7. 执行 `SELECT *` 查询

+ 可以看到，查询被直接拦截并终止，未被实际执行。

  ```sql
  SELECT * FROM sbtest1;
  ```

  ```output
  tidb:db1> SELECT * FROM sbtest1;
  ERROR 8254 (HY000): Quarantined and interrupted because of being in runaway watch list
  ```

### 步骤 8. 再次查看监控（WATCH）列表

+ 再次查看 Runaway Query 监控列表，可以看到当前有两条监控规则。

  ```sql
  SELECT * from information_schema.runaway_watches ORDER BY id\G
  ```

  ```output
  tidb:db1> SELECT * from information_schema.runaway_watches ORDER BY id\G
  *************************** 1. row ***************************
                  ID: 1
  RESOURCE_GROUP_NAME: rg1
          START_TIME: 2025-07-15 01:13:54
            END_TIME: 2025-07-15 02:53:54
                WATCH: Similar
          WATCH_TEXT: a7a2fbb8a227456777fd6d3dd68dee4089cb05413ccac0f3731d2fa538a09dea
              SOURCE: 10.90.2.141:4000
              ACTION: Kill
                RULE: ProcessedKeys = 1095654(100)
  *************************** 2. row ***************************
                   ID: 2
  RESOURCE_GROUP_NAME: rg1
           START_TIME: 2025-07-15 01:17:38
             END_TIME: UNLIMITED
                WATCH: Similar
           WATCH_TEXT: 35c978d76693ff8e8db1c5cb395ed9a09408c04deb295e4e78dbadedccd18fd6
               SOURCE: manual
               ACTION: Kill
                 RULE: None
  2 rows in set (0.00 sec)
  ```
