DB 23cよりLock Free Reservationと呼ばれる機能が追加されました。これは以下の操作を行います。
- 数値列の操作を加算と減算に限定します。
- 演算結果を更新する代わりに、差分をジャーナルに保存します。
- 値が書かれているブロックは変更しないため、ロックを取得しません。値自体は変更されたように見えます。
- 別のトランザクションが同じ行の同じ列を更新する場合も、ロックを取得せずに差分をジャーナルに保存するので待機が発生しません。
- トランザクションのコミット時に差分を適用します。
- SAGAが開始していて(DBMS_SAGA.BEGIN_SAGAが呼び出された後)、SAGAのロールバックが発生した(DBMS_SAGA.ROLLBACK_SAGAが呼びされる)場合は、自動的に補償トランザクションが実行されます。
この機能を実装してみて、実際に効果を確認してみます。SAGAの実装は大変なので、それは除きます。また、仕組みの詳細について解説することは、目的としていません。
効果の確認に、Oracle REST Data ServicesのRESTサービスを使います。
最初に表CALL_COUNTERを作成します。
create table call_counter(
id number primary key,
count number
);あらかじめ1行データを投入します。主キーIDの値は1です。UPDATEを実行するときは、条件として主キーの値を指定する必要があります。
Lock Free Reservationを有効にする場合は、以下のようにreservableを指定します。
RESTfulサービスのモジュールとしてcall、テンプレートとしてcountを作成し、GETハンドラを作成します。ソース・タイプはPL/SQLを選択します。
alter table call_counter modify (count reservable);
create table call_counter(
id number primary key,
count number reservable
);
最初に、Lock Free Reservationなしで作業を進めます。以下のコードがGETハンドラの処理になります。
id number primary key,
count number reservable
);
最初に、Lock Free Reservationなしで作業を進めます。以下のコードがGETハンドラの処理になります。
テストの準備ができたので、同時にRESTサービスを呼び出してみます。RESTサービスの待機時間を含む処理時間は、5、9、12、16秒と増えていきます。countは52、53、54、55となっています。
列countをreservableに変更します。
alter table call_counter modify (count reservable);
ほとんどのリクエストが5秒で終了します。ロック待機が発生していないことが確認できます。また、逐次処理にはなっていないため、countは全部同じ値(以下では55)です。次にRESTサービスを呼び出すと、countは4が加わり59になります。
Lock Free Reservationには、このような効果があります。
reservableとなっている列がある表をドロップしようとすると、ORA-55764が発生します。そのため、表をドロップする前に列をnon reservableに変更する必要があります。
SQL> drop table call_counter;
drop table call_counter
*
ERROR at line 1:
ORA-55764: Cannot DROP or MOVE tables with reservable columns. First run "ALTER
TABLE <table_name> MODIFY (<reservable_column_name> NOT RESERVABLE)" and then
DROP or MOVE the table.
SQL>
ここまで極端なホットスポットはあまり無いとは思います。とはいえ加算と減算に操作を限定できる数値列、例えばページの訪問数やいいねをクリックした数のようなデータがある場合は、適用を検討する価値はあるでしょう。
完