mita2 database life

主にMySQLに関するメモです

TiDB metadata lock で DDL が待たされた時の調査方法

前提

本エントリーは、tidb_enable_metadata_lock が ON であることを前提としています。

mysql> SELECT @@transaction_isolation, @@tidb_enable_metadata_lock, @@version;
+-------------------------+-----------------------------+--------------------+
| @@transaction_isolation | @@tidb_enable_metadata_lock | @@version          |
+-------------------------+-----------------------------+--------------------+
| REPEATABLE-READ         |                           1 | 8.0.11-TiDB-v8.1.2 |
+-------------------------+-----------------------------+--------------------+
1 row in set (0.00 sec)

DDLをブロックしているトランザクションの調査方法

TiDB にも MySQL 同様に metadata lock があり、DDLがクエリによってブロックされることがあります。

mysql.tidb_mdl_view でブロックしているトランザクションを確認できます。 metadata lock が競合せず、ブロックが発生していない場合は、何も表示されません。

tidb_mdl_view は、実行済みのクエリも含めて、ブロックしているトランザクションに含まれる全てのクエリを SQL_DIGESTS に出力してくれます。これは非常に便利ですね。 start_time も、直近のクエリの開始時間ではなく、トランザクションの開始時間です。

mysql>  SELECT * FROM mysql.tidb_mdl_view;
+--------+---------+------------+--------------------------------+------------+----------------------------+-------------------------------------------+
| job_id | db_name | table_name | query                          | session_id | start_time                 | SQL_DIGESTS                               |
+--------+---------+------------+--------------------------------+------------+----------------------------+-------------------------------------------+
|    108 | t       | t          | ALTER TABLE t ADD INDEX idx(a) | 3212836870 | 2025-09-11 21:01:30.919000 | ["begin","select `a` , now ( ) from `t`"] |
+--------+---------+------------+--------------------------------+------------+----------------------------+-------------------------------------------+
1 row in set (0.00 sec)

さて、ここで、追加のトランザクションを実行します。 なお、MySQL では MDL 待ち状態で、追加のトランザクションを実行すると、そのトランザクションは待たされますが、TiDB では DDL を追い越して、トランザクションを実行することができます(その代わり、後続のトランザクションが先行するDDLをブロックします)。

mita2db.hateblo.jp

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

mysql> SELECT a, NOW() AS 2ndtry FROM t;
+------+---------------------+
| a    | 2ndtry              |
+------+---------------------+
|    1 | 2025-09-11 21:04:27 |
+------+---------------------+
1 row in set (0.00 sec)

tidb_mdl_view にも行が追加されることがわかりました。

mysql> mysql>  SELECT * FROM mysql.tidb_mdl_view;
+--------+---------+------------+--------------------------------+------------+----------------------------+-----------------------------------------------+
| job_id | db_name | table_name | query                          | session_id | start_time                 | SQL_DIGESTS                                   |
+--------+---------+------------+--------------------------------+------------+----------------------------+-----------------------------------------------+
|    108 | t       | t          | ALTER TABLE t ADD INDEX idx(a) | 3212836870 | 2025-09-11 21:01:30.919000 | ["begin","select `a` , now ( ) from `t`"]     |
|    108 | t       | t          | ALTER TABLE t ADD INDEX idx(a) | 3212836876 | 2025-09-11 21:04:26.073000 | ["select `a` , now ( ) as `2ndtry` from `t`"] |
+--------+---------+------------+--------------------------------+------------+----------------------------+-----------------------------------------------+
2 rows in set (0.00 sec)

トランザクションをコミット/ロールバックすると、tidb_mdl_view から消えます(そしてDDLの実行が開始されます)。