mita2 database life

主にMySQLに関するメモです

TiDB MySQLとの細かな非互換 - SELECT ~ FOR UPDATE SKIP LOCKED 編

SKIP LOCKED はサポートされていないが通ってしまう

TiDB 8.5 時点では SELECT ~ FOR UPDATE SKIP LOCKED はサポートされていません。 しかし、エラーにならずに通ってしまいます。

マニュアルには、「サポートされていない」とは書いてあるのですが、「無視する」とまでは書いてなさそう。

Unsupported features SKIP LOCKED syntax #18207

docs.pingcap.com

MySQL の場合

SKIP LOCKEDMySQL 8.0 でサポートされました。すでにロックされている行を除いて、ロックされてない行のみを返します(ロックを取ります)。 言うまでもありませんが、それ以前のバージョンでは文法エラーになります。

pk1 のレコードのロックを取ります。

mysql> SELECT * FROM tbl;
+----+
| pk |
+----+
|  1 |
|  2 |
|  3 |
+----+
3 rows in set (0.00 sec)

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

mysql> SELECT * FROM tbl WHERE pk = 1 FOR UPDATE;
+----+
| pk |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

pk1 以外のレコードが SELECT されます。

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

mysql> SELECT * FROM tbl FOR UPDATE SKIP LOCKED;
+----+
| pk |
+----+
|  2 |
|  3 |
+----+
2 rows in set (0.00 sec)

TiDB の場合

同じように pk1 のレコードのロックを取ります。

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

mysql> SELECT * FROM tbl WHERE pk = 1 FOR UPDATE \G
*************************** 1. row ***************************
pk: 1
1 row in set (0.00 sec)

別のセッションで、SELECT ~ FOR UPDATE SKIP LOCKED を実行すると、pk1 のレコードも SELECT 出来てしまいます。 サポートしてないなら、エラーにしてほしい。。。。

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

-- ちなみに、tidb_enable_noop_functions は OFF でも同じ
mysql> SELECT * FROM tbl FOR UPDATE SKIP LOCKED \G
*************************** 1. row ***************************
pk: 1
*************************** 2. row ***************************
pk: 2
*************************** 3. row ***************************
pk: 3
3 rows in set (0.00 sec)

-- 確かに pk = 1  の行はロックされている。
mysql> SELECT * FROM tbl WHERE pk = 1 FOR UPDATE \G
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

tidb_txn_mode = pessimistic (デフォルト) での動作確認しています。