テーブルロックは最も基本的なロック戦略であり、OceanBaseデータベースは単一のテーブル、複数のテーブル、およびテーブルの複数のパーティションとサブパーティションに対するロックをサポートしています。
データベースは複数のユーザーが共有するリソースです。複数のユーザーが同時にデータにアクセスすると、データベース内では複数のトランザクションが同一のデータに同時にアクセスする状況が発生します。このような並行操作を制御しない場合、正しくないデータが読み取られたり保存されたりし、データベースの整合性が損なわれる可能性があります。ロックは、データベースの並行処理を制御するための非常に重要な技術です。リソースの安全性(つまりデータの完全性と整合性)を確保するために、ロックメカニズムが導入されました。このロックメカニズムを利用して、トランザクション間のデータの並行アクセスとデータの整合性を実現します。
テーブルがロックされると、ロックされたテーブルは、トランザクションがコミットされるか、またはトランザクションがロールバックされる(テーブルがロックされる前のセーブポイントまでロールバックされる)まで、そのロック状態を維持します。トランザクション制御文の詳細については、トランザクション制御文を参照してください。
テーブルロックモード
OceanBaseデータベースの現行バージョンでサポートされているロックモードは以下のとおりです:
- ROW SHARE:ロックされたテーブルへの並行アクセスを許可しますが、他のユーザーによるテーブル全体の排他的なアクセス(つまり、テーブル上の
EXCLUSIVEロック)を禁止します。 - ROW EXCLUSIVE:他のユーザーによる
SHARE以上(すなわちSHARE、ROW SHARE EXCLUSIVE、EXCLUSIVE)のモードでのテーブルロックを禁止します。更新、挿入、削除、またはSELECT FOR UPDATE操作を実行する際には、自動的にROW EXCLUSIVEロックが取得されます。 - SHARE:並行クエリを許可しますが、ロックされたテーブルへの更新を禁止します。SHAREロックは、テーブル内の行に対する更新(
UPDATE、DELETE、INSERT)およびSELECT FOR UPDATE操作を阻止すると同時に、テーブルに対するより高度なレベルのロックも阻止します。つまり、他のユーザーによるテーブル上のSHARE ROW EXCLUSIVEおよびEXCLUSIVEロックを禁止します。 - SHARE ROW EXCLUSIVE:他のユーザーがテーブル内の行を参照することを許可しますが、行の更新(
UPDATE、DELETE、INSERT)やSELECT FOR UPDATEによるテーブル内の行のクエリ、およびテーブル上のROW SHARE以外のモードのロックを禁止します。 - EXCLUSIVE:他のユーザーがロックされたテーブルに対してクエリのみを実行することを許可し、他のユーザーによるテーブル上での任意のタイプのDMLステートメントや任意のタイプのロックを禁止します。
各モードにおけるロック競合関係は、以下の表のとおりです:
| リクエストロックモード | 現在のロックモード | |||||
|---|---|---|---|---|---|---|
| ROW SHARE | ROW EXCLUSIVE | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ||
| ROW SHARE | 競合なし | 競合なし | 競合なし | 競合なし | 競合 | |
| ROW EXCLUSIVE | 競合なし | 競合なし | 競合 | 競合 | 競合 | |
| SHARE | 競合なし | 競合 | 競合なし | 競合 | 競合 | |
| SHARE ROW EXCLUSIVE | 競合なし | 競合 | 競合 | 競合 | 競合 | |
| EXCLUSIVE | 競合 | 競合 | 競合 | 競合 | 競合 | |
権限要件
ロック対象のテーブルは、ユーザー自身のスキーマ内に存在する必要があります。または、ユーザーはLOCK ANY TABLEシステム権限を持っている必要があります。
テーブル全体のロック
テーブル全体をロックするSQL文は以下のとおりです:
LOCK TABLE [schema.]table_name[,[schema.]table_name ...] IN lockmode MODE [NOWAIT | WAIT integer];
文の使用方法:
table_name:ロック対象のテーブル名を指定します。複数のテーブルを指定する場合は、英語のカンマ(,)で区切ります。lockmode:テーブルロックモードを指定します。NOWAIT | WAIT integer:ロック競合が発生した場合の処理方法を指定します。NOWAITを指定した場合、ターゲットテーブルに対するロック時にロック競合が発生すると、システムは直ちに制御権をユーザーに返し、エラーメッセージを返します。WAIT integerを指定した場合、ターゲットテーブルに対するロック時にロック競合が発生すると、システムは競合しているテーブルのロックが解放されるまで待機します。ユーザーが設定したステートメント実行のタイムアウト時間を超えても、その競合するテーブルのロックが解放されない場合、システムはエラーメッセージを返します。ここで、integerの単位は秒であり、その値に制限はありません。注意
WAIT integerを指定した場合、ステートメント実行のタイムアウト時間はinteger、ob_query_timeout および ob_trx_timeout の値によって決まり、これら3つのうち最小値がステートメント実行の実際のタイムアウト時間となります。例えば、WAIT 10を指定し、かつob_query_timeout、ob_trx_timeoutがデフォルト値の場合、ロック競合の待機タイムアウト時間は1000000 us、すなわち1秒となります。NOWAITとWAIT integerの両方を指定しない場合、ステートメント実行のタイムアウト時間は ob_query_timeout と ob_trx_timeout の間の最小値によって決まります。
テーブル tbl1 にEXCLUSIVEロックをかける例を以下に示します。
LOCK TABLE tbl1 IN EXCLUSIVE MODE NOWAIT;
この例では、テーブル tbl1 にEXCLUSIVEロックをかけた後、他のユーザーはそのテーブルをクエリすることはできますが、そのテーブルに対してDMLステートメントを実行したり、他の任意の種類のロックをかけたりすることはできません。
テーブルのパーティションロック
テーブルのパーティションをロックするSQL文は以下のとおりです:
LOCK TABLE
{
[ schema.]table_name
[ PARTITION '('partition_name ...')' | SUBPARTITION '(' subpartition_name ...')' ] ...
}
IN lockmode MODE
[ NOWAIT | WAIT integer] ;
文の使用方法:
table_name:ロック対象のパーティションテーブルの名前を指定します。partition_name:ロック対象のパーティションの名前を指定します。複数のパーティションを同時にロックでき、パーティション名は英語のカンマ(,)で区切ります。subpartition_name:ロック対象のサブパーティションの名前を指定します。複数のサブパーティションを同時にロックでき、サブパーティション名は英語のカンマ(,)で区切ります。lockmode:テーブルロックモードを指定します。NOWAIT | WAIT integer:ロック競合が発生した場合の処理方法を指定します。NOWAITを指定した場合、ターゲットテーブルへのロック時にロック競合が発生すると、システムは直ちに制御権をユーザーに返し、エラーメッセージを返します。WAIT integerを指定した場合、ターゲットテーブルへのロック時にロック競合が発生すると、システムは競合するテーブルロックが解放されるまで待機します。ユーザーが設定したステートメント実行のタイムアウト時間を超えても競合するテーブルロックが解放されない場合、システムはエラーメッセージを返します。ここで、integerの単位は秒であり、その値に制限はありません。注意
WAIT integerを指定した場合、ステートメント実行のタイムアウト時間はinteger、ob_query_timeout および ob_trx_timeout の値によって決まり、これら3つのうち最小値がステートメント実行の実際のタイムアウト時間となります。例えば、WAIT 10を指定し、かつob_query_timeout、ob_trx_timeoutがデフォルト値の場合、ロック競合の待機タイムアウト時間は1000000 us、すなわち1秒となります。NOWAITとWAIT integerのいずれも指定しない場合、ステートメント実行のタイムアウト時間は ob_query_timeout と ob_trx_timeout の間の最小値によって決まります。
以下に例を示します。現在のデータベースに、テンプレート化されたサブパーティションテーブル tbl2 があり、その作成ステートメントは以下のとおりです。
CREATE TABLE tbl2(col1 NUMBER, col2 NUMBER)
PARTITION BY RANGE (col1)
SUBPARTITION BY RANGE (col2)
SUBPARTITION TEMPLATE
(
SUBPARTITION sp0 VALUES LESS THAN (3),
SUBPARTITION sp1 VALUES LESS THAN (6),
SUBPARTITION sp2 VALUES LESS THAN (9)
)
(
PARTITION p0 VALUES LESS THAN (100),
PARTITION p1 VALUES LESS THAN (200),
PARTITION p2 VALUES LESS THAN (300)
);
パーティションテーブルを作成した後、テンプレート化されたサブパーティションテーブルのパーティション命名規則に基づき、作成されたサブパーティション名はそれぞれ p0ssp0、p0ssp1 および p0ssp2 となります。パーティション命名規則の詳細については、パーティションの概要 を参照してください。
次に、このテーブルに対して以下のロック操作を実行します:
テーブル
tbl2のパーティションp1にEXCLUSIVEロックをかけます。LOCK TABLE tbl2 PARTITION (p1) IN EXCLUSIVE MODE NOWAIT;テーブル
tbl2のサブパーティションp1ssp1にEXCLUSIVEロックをかけます。LOCK TABLE tbl2 SUBPARTITION (p1ssp1) IN EXCLUSIVE MODE WAIT 60;テーブル
tbl2のパーティションp1、p2およびサブパーティションp2ssp0、p2ssp1にSHAREロックをかけます。LOCK TABLE tbl2 PARTITION (p1, p2), tbl2 SUBPARTITION (p2ssp0, p2ssp1) IN SHARE MODE;
テーブルロックの確認
テーブルにロックをかけた後、ビューGV$OB_LOCKSおよびV$OB_LOCKSを使用して、現在のユーザーが各テーブルで保持または要求しているロック状況を確認できます。
SELECT * FROM GV$OB_LOCKS;
クエリ結果の例です。
+----------------+----------+-----------+----------+------+--------+------+-------+---------+-----------+-------+
| SVR_IP | SVR_PORT | TENANT_ID | TRANS_ID | TYPE | ID1 | ID2 | LMODE | REQUEST | CTIME | BLOCK |
+----------------+----------+-----------+----------+------+--------+------+-------+---------+-----------+-------+
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 500003 | NULL | RX | NONE | 462723786 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 500003 | NULL | RS | NONE | 6690958 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200005 | NULL | X | NONE | 462718854 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200006 | NULL | X | NONE | 462710583 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200007 | NULL | X | NONE | 462701111 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200005 | NULL | S | NONE | 6687863 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200006 | NULL | S | NONE | 6679696 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200007 | NULL | S | NONE | 6671395 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200008 | NULL | S | NONE | 6661725 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200009 | NULL | S | NONE | 6653562 | 0 |
| xx.xx.xx.xx | 2882 | 1004 | 1344711 | TM | 200010 | NULL | S | NONE | 6645387 | 0 |
+----------------+----------+-----------+----------+------+--------+------+-------+---------+-----------+-------+
11 rows in set
クエリ結果の一部のフィールドについては、以下の表のとおり説明します。
| フィールド名 | 説明 |
|---|---|
| SRV_IP | ロックを保持またはロックを要求しているOBServerノードのIPアドレス |
| SRV_PORT | ロックを保持またはロックを要求しているOBServerノードのポート番号 |
| TENANT_ID | ロックを保持またはロックを要求しているテナントのID |
| TRANS_ID | ロックを保持またはロックを要求しているトランザクションのID |
| TYPE | ロックタイプ:
|
| ID1 | ロック識別子1:
|
| ID2 | ロック識別子2:
|
| LMODE | 現在保持されているロックのモード:
|
| REQUEST | 現在要求されているロックのモード:
|
| CTIME | ロックを保持または待機している時間、単位はマイクロ秒 |
| BLOCK | ロックが他のプロセスをブロックしているかどうかを示します:
|
詳細情報
LOCK TABLES ステートメントの詳細については、LOCK TABLESを参照してください。