Database Support Blog

  • Oracle Database
2025.04.08

【Oracle Database 23ai 検証】ロックフリー予約で効率的なデータ更新を実現しよう!

アシストでは、日本オラクル社の協力を得てOracle Database 23aiの検証プログラムを行っています。
第4回となる本記事では、23aiの新機能である「ロックフリー予約」を紹介します。この新機能を活用することで複数トランザクションの同時実行性を向上させ、システムのパフォーマンス改善を図ることができます。

  • ロックフリー予約はEnterprise Editionで利用可能な機能です。

ロックフリー予約とは

通常、行の列値を更新すると、トランザクションが完了するまで対象行がロックされます。このとき他のセッションはロックされた行を変更できず、トランザクションが完了するまで待機となります。
この行ロックはデータの整合性を保つ上では重要な仕組みですが、更新処理によるトランザクションが同時に多数実行される場面では、行ロックの競合による待機時間が増えることでパフォーマンスが低下します。

そこで23aiのロックフリー予約を使用すると、数値列のデータに対して、整合性を保ちつつ更新処理による行ロックの競合を回避できます。これにより、トランザクションの同時実行性が大幅に向上します。ユースケースとしては、商品の在庫数や、航空券などの座席数、銀行口座残高など数値データの更新を効率化することができます。

これまでロックフリー予約と同等の動作を実現したい場合には、開発者が仕組みを検討し実装する必要がありましたが、23aiからは、このようにロックフリー予約で簡単に実装できるようになりました。

ロックフリー予約の使い方

1.事前準備

ロックフリー予約を利用するには、表を作成または変更するときにRESERVABLE句で予約可能列を定義します。この予約可能列には、更新処理で行ロックを獲得したくない列に対して指定します。
※予約可能列には数値データ型(NUMBER、INTEGERおよびFLOAT)のみ指定できます。

– quantity列を予約可能列としてtest表を作成
SQL> CREATE TABLE test
  2  ( id NUMBER PRIMARY KEY,
  3    name VARCHAR2(10),
  4    quantity NUMBER RESERVABLE CONSTRAINT minimum_count CHECK (quantity >= 0)
  5  );
表が作成されました。


今回はquantity列を予約可能列としました。併せてチェック制約で「列値は0以上を満たす」ことを定義しています。

予約可能列を指定して表を作成すると、「ジャーナル表」という予約可能列を管理するための内部表が自動で作成されます。このジャーナル表にはトランザクションで更新された数値の増減などが記録されます。

– 作成されたジャーナル表の確認
SQL> SELECT object_id, object_name, object_type FROM user_objects;
OBJECT_ID OBJECT_NAME OBJECT_TYPE ---------- -------------------- -------------------- 109006 TEST TABLE 109007 SYS_RESERVJRNL_109006 TABLE — > 作成されたジャーナル表

2.ロックフリーなトランザクションの実行

ここからは、予約可能列のquantity列に対して3つのセッションから更新処理を行います。まずはセッション1でUPDATE文を実行し、行ロックの状況を確認します。

▼セッション1

– 現在のquantity列の値は「50」
SQL> SELECT * FROM test;
ID NAME QUANTITY ---------- ---------- ---------- 1 AAA 50
– quantity列値から10減算する SQL> UPDATE test SET quantity = quantity - 10 WHERE id=1; 1行が更新されました。
– 管理ユーザーから行ロック(TXロック)の状況を確認 SQL> SELECT block FROM v$lock WHERE sid = 272 and type='TX';
BLOCK ---------- 0


V$LOCKビューの問い合わせ結果から、セッション1で実行したUPDATE文の行ロックが獲得されていないことが分かりますね。

続いて、ジャーナル表も見てみましょう。

– ジャーナル表の確認
SQL> SELECT * FROM SYS_RESERVJRNL_109006;
ORA_SAGA_ID$ ORA_TXN_ID$ ORA_STATUS$ ORA_ST ID QUANTITY_OP QUANTITY_RESERVED ------------- --------------- ----------- ------ -------- ----------- ----------------- 04001D00540D000 ACTIVE UPDATE 1 - 10


右の2列で「- 10」とあるように、ジャーナル表にはquantity列の数値の増減が記録されています。このようにジャーナル表でデータ更新の履歴が管理されることで、行ロックを獲得しなくてもデータの整合性が保たれる仕組みになっています。

次に、セッション2でセッション1が更新中のquantity列値から20減算するUPDATE文を実行します。

▼セッション2

– quantity列値から20減算する
SQL> UPDATE test SET quantity = quantity - 20 WHERE id=1;
1行が更新されました。
– ジャーナル表の確認 SQL> SELECT * FROM SYS_RESERVJRNL_109006;
ORA_SAGA_ID$ ORA_TXN_ID$ ORA_STATUS$ ORA_ST ID QUANTITY_OP QUANTITY_RESERVED ------------- --------------- ----------- ------ -------- ----------- ----------------- 090002006211000 ACTIVE UPDATE 1 - 20

通常、セッション2はセッション1のトランザクションが完了するまで待機となりますが、待機せずに処理を続けることができていますね。
また、セッション2のジャーナル表を確認すると、セッション2が実行した「-20」の処理が記録されています。この結果から分かるように、ジャーナル表では他セッションの情報は見れず、自セッションの情報のみを確認できます。

続いて、セッション3でquantity列値から30減算するUPDATE文を実行します。

▼セッション3

– quantity列値から30減算する
SQL> UPDATE test SET quantity = quantity - 30 WHERE id=1;
UPDATE test SET quantity = quantity - 30 WHERE id=1
*
行1でエラーが発生しました。:
ORA-02290: チェック制約(SCOTT.MINIMUM_COUNT)に違反しました
ヘルプ:https://docs.oracle.com/error-help/db/ora-02290


セッション3ではチェック制約違反によるエラーが発生しました。現在quantity列値は”50”ですが、セッション1で”10”、セッション2で”20”減算中のため、セッション3で”30”減算すると「列値は0以上を満たす」というチェック制約に違反します。
このように、ロックフリー予約とチェック制約を組み合わせると、確定(コミット)されていないトランザクションのデータを考慮した上で、制約に違反しないことが保証されます。

続いて、セッション2で20減算していた処理をコミットします。

SQL> COMMIT;
コミットが完了しました。
SQL> SELECT * FROM test; ID NAME QUANTITY ---------- ---------- ---------- 1 AAA 30


変更が確定され、quantity列値が50→30に更新されました。またセッション内のトランザクションが完了すると、ジャーナル表の対象トランザクションの情報も削除されます。

SQL> SELECT * FROM SYS_RESERVJRNL_109006;
レコードが選択されませんでした。

3.制限事項

ロックフリー予約には制限事項が多く存在します。
例えば、予約可能列に対する更新処理は「-10」や「+10」といった数値の増減のみが可能です。以下のように、数値を直接指定するUPDATE文の実行はできません。

– UPDATE処理で更新後の数値を直接指定
SQL> UPDATE test SET quantity =30;
UPDATE test SET quantity =30
      *
行1でエラーが発生しました。:
ORA-55746: 予約可能列のUPDATE文は、予約可能列に対する+または-演算のみをサポートしています。 
ヘルプ:https://docs.oracle.com/error-help/db/ora-55746/

また、予約可能列と非予約可能列を同時に更新することはできないといった制限もあります。

– 予約可能列(quantity列)と非予約可能列(id列)を更新
SQL> UPDATE test SET id=2,quantity=30 WHERE id=1;
UPDATE test SET id=2,quantity=30 WHERE id=1
       *
行1でエラーが発生しました。:
ORA-55735: 予約可能列と非予約可能列を同じ文で更新することはできません。 
ヘルプ:https://docs.oracle.com/error-help/db/ora-55735/


ロックフリー予約を利用される際は、これらの条件を満たせるか確認の上ご利用ください。

 ■その他の制限事項(抜粋)
 ・予約可能列は、Oracle数値データ型(NUMBER、INTEGERおよびFLOAT)の列にのみ指定できる。
 ・予約可能列が含まれる表には、Primary Key制約が必要となる。
 ・予約可能列では、索引はサポートされない。 など

 ※上記以外の制限事項はオラクル社のマニュアルをご確認ください。
  データベース開発ガイド 23ai (オラクル社のサイトに移動します)
  ロックフリー予約のガイドラインと制限事項

最後に

本記事では、データの整合性を保ちつつ同時実行性を向上させることができる、ロックフリー予約についてご紹介しました。今回は3つのセッションを例に使い方をご紹介しましたが、オンライン系の処理で、多数のトランザクションによる行ロックの競合がパフォーマンスの問題となる環境では、ロックフリー予約を検討してみてはいかがでしょうか。

アシストでは引き続き、23aiの様々な機能についてご紹介します。次回連載もお楽しみにお待ちください!



この記事で知りたい情報は得られましたか?

本記事に関連して、他にもOracle Database 23aiの新機能や機能拡張についてご紹介している記事もございます。あわせてご活用ください。


執筆者情報

かじやま あさこ プロフィール画像

2015年入社後、Oracle Databaseのフィールドエンジニアとして構築支援などに従事。
現在はデータベース研修の講師/運営/企画を担当。趣味は最近始めたヨガ。...show more


■本記事の内容について
 本記事に示した定義及び条件は変更される場合があります。あらかじめご了承ください。

■商標に関して
 ・Oracle®、Java、MySQL及びNetSuiteは、Oracle、その子会社及び関連会社の米国及びその他の国における登録商標です。
 ・Amazon Web Services、AWS、Powered by AWS ロゴ、[およびかかる資料で使用されるその他の AWS 商標] は、Amazon.com, Inc. またはその関連会社の商標です。
  文中の社名、商品名等は各社の商標または登録商標である場合があります。

関連している記事

  • Oracle Cloud
  • Oracle Database
2025.04.18

Oracle Cloud VMware SolutionでのVMware HCX環境構築手順(後編)

前回の記事でOCVS)でHCXを利用するための前提となる手順の前半をお伝えしました。本記事では後続の手順であるサービスメッシュ作成・L2延伸手順を記載し、仮想マシンを移行できる状態、つまりHCX環境の構築完了までを説明します。

  • Oracle Database
2025.04.11

【Oracle Database 23ai 検証】読取り専用モードの機能拡張

23aiで読取り専用モードの機能が拡張されました。ユーザー/セッション単位で読み書き可能/読取り専用モードの使い分けができるようになり、今まで以上にメンテナンス操作やアプリケーションからの接続の権限管理が柔軟にできるようになっています。

  • Oracle Database
2025.03.27

【Oracle Database 23ai 検証】統合監査のキホンと拡張機能について

Oracle Database 23aiでは、従来型監査が非サポートとなるため、代替機能である統合監査を使用いただく必要があります。統合監査の基本概念とその新機能についてご紹介します。

ページの先頭へ戻る