業務運用において、ユーザーはしばしばロック競合の問題に直面します。行ロックには、それと密接に関連する2つのオブジェクトがあります:行ロックの保持者と行ロックの待機者です。これら2つのオブジェクトは、行ロックの調査・分析プロセスにおいて重要な役割を果たします。本質的に、行ロックの競合はすべてトランザクションによって引き起こされるものであり、これら2つのオブジェクトもいずれもトランザクションに属しています。したがって、行ロックの問題を処理する際には、アクティブなトランザクションの監視も必要となります。
ロックを保持またはロックを要求しているトランザクションの関連情報の確認
ビュー GV$OB_LOCKS には、現在ユーザーが各テーブルで保持または要求しているロックの状況が記録されています。このビューでは主に以下の3種類のロックが表示されます:
- テーブルロック(TM):テーブルまたはパーティション(Tablet)上のロックです。通常、insert / update / deleteなどのDML操作はパーティションレベルのテーブルロックを生成し、DDL操作はテーブルレベルのテーブルロックを生成します。
- 行ロック(TR):行を書き込む際にかけられるロックです。
- トランザクションロック(TX):最も一般的なロックで、通常はトランザクション内で書き込み操作を行った場合に生成されると理解できます。
OceanBaseデータベースでは、トランザクションが行ロックを保持している場合、必ず自身のトランザクションロックも保持しています。
以下の方法で、ロックを保持またはロックを要求しているトランザクションの関連情報を確認できます。
システムテナント
システムテナントでは、以下のステートメントを使用してクエリを実行できます。
obclient> SELECT t.TENANT_ID, t.TRANS_ID, t.TYPE, t.ID1, t.ID2, t.LMODE, t.REQUEST, ROUND(t.CTIME / 1000000) CTIME_s, t.BLOCK FROM oceanbase.gv$ob_locks t WHERE t.BLOCK = 1 ORDER BY t.TRANS_ID;ユーザーテナント
MySQLモードのユーザーテナントでは、以下のステートメントを使用してクエリを実行できます。
obclient> SELECT t.TRANS_ID, t.TYPE, t.ID1, t.ID2, t.LMODE, t.REQUEST, ROUND(t.CTIME / 1000000) CTIME_s, t.BLOCK FROM oceanbase.gv$ob_locks t WHERE t.BLOCK = 1 ORDER BY t.TRANS_ID;Oracleモードのユーザーテナントでは、以下のステートメントを使用してクエリを実行できます。
obclient> SELECT t.TRANS_ID, t.TYPE, t.ID1, t.ID2, t.LMODE, t.REQUEST, ROUND(t.CTIME / 1000000) CTIME_s, t.BLOCK FROM SYS.gv$ob_locks t WHERE t.BLOCK = 1 ORDER BY t.TRANS_ID;
例えば、システムテナントのクエリ結果は次のとおりです:
+-----------+----------+------+----------+--------------------------------+-------+---------+---------+-------+
| TENANT_ID | TRANS_ID | TYPE | ID1 | ID2 | LMODE | REQUEST | CTIME_s | BLOCK |
+-----------+----------+------+----------+--------------------------------+-------+---------+---------+-------+
| 1002 | 23723243 | TR | 200051 | 23723237-{"BIGINT UNSIGNED":1} | NONE | X | 20 | 1 |
| 1002 | 23723243 | TX | 23723237 | NULL | NONE | X | 20 | 1 |
+-----------+----------+------+----------+--------------------------------+-------+---------+---------+-------+
2 rows in set
最初の行の結果から、現在1つの行ロック(TR)情報があり、ロックを要求しているトランザクションのID(TRANS_IDフィールド)は23723243、ロック対象のtablet_id(ID1フィールド)は200051、ロックされた行の情報(ID2フィールド)は23723237-{"BIGINT UNSIGNED":1}、ロック待ち時間は20秒であることがわかります。
2番目の行の結果から、現在1つのトランザクションロック(TX)情報があり、ロックを要求しているトランザクションのID(TRANS_IDフィールド)は23723243、ロックを保持しているトランザクションのID(ID1フィールド)は23723237であることがわかります。
trans_idに基づいてトランザクションの対応するsession_idを照会する
ビューGV$OB_TRANSACTION_PARTICIPANTSは、すべてのOBServerノード上でアクティブなトランザクションの参加者情報を記録しています。
ロックを保持またはロックを要求しているトランザクションのtrans_idを取得した後、ビューGV$OB_TRANSACTION_PARTICIPANTSを照会することで、そのトランザクションに対応するsession_idを取得できます。
システムテナント
システムテナントでは、以下のステートメントを使用して照会できます。
obclient> SELECT ROUND(now() - t.CTX_CREATE_TIME) RUNNING_TIME_s, t.TENANT_ID, t.SVR_IP, t.SVR_PORT, t.SESSION_ID, t.TX_TYPE, t.TX_ID, t.STATE, t.ACTION, t.CTX_CREATE_TIME, t.LAST_REQUEST_TIME FROM oceanbase.GV$OB_TRANSACTION_PARTICIPANTS t WHERE t.TX_ID IN (holdlock_trans_id, requestlock_trans_id);ユーザーテナント
MySQLモードのユーザーテナントでは、以下のステートメントを使用して照会できます。
obclient>SELECT ROUND(now() - t.CTX_CREATE_TIME) RUNNING_TIME_s, t.TENANT_ID, t.SVR_IP, t.SVR_PORT, t.SESSION_ID, t.TX_TYPE, t.TX_ID, t.STATE, t.ACTION, t.CTX_CREATE_TIME, t.LAST_REQUEST_TIME FROM oceanbase.GV$OB_TRANSACTION_PARTICIPANTS t WHERE t.TX_ID IN (holdlock_trans_id, requestlock_trans_id);Oracleモードのユーザーテナントでは、以下のステートメントを使用して照会できます。
obclient>SELECT ROUND(now() - t.CTX_CREATE_TIME) RUNNING_TIME_s, t.TENANT_ID, t.SVR_IP, t.SVR_PORT, t.SESSION_ID, t.TX_TYPE, t.TX_ID, t.STATE, t.ACTION, t.CTX_CREATE_TIME, t.LAST_REQUEST_TIME FROM SYS.GV$OB_TRANSACTION_PARTICIPANTS t WHERE t.TX_ID IN (holdlock_trans_id, requestlock_trans_id);
ステートメント内で:
running_time_s:トランザクション実行の合計時間。holdlock_trans_id:ロックを保持しているトランザクションのID。requestlock_trans_id:ロックを要求しているトランザクションのID。
ロックを保持しているトランザクションに対応するsession_idを取得した後、kill session_idを使用して対応するトランザクションをロールバックできます。