2023年4月12日水曜日

DB 23cのLock Free Reservationを使ってみる

 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の値はです。UPDATEを実行するときは、条件として主キーの値を指定する必要があります。

insert into call_counter(id, count) values(1, 0);

Lock Free Reservationを有効にする場合は、以下のようにreservableを指定します。

create table call_counter(
    id number primary key,
    count number reservable
);


最初に、Lock Free Reservationなしで作業を進めます。以下のコードがGETハンドラの処理になります。


RESTfulサービスのモジュールとしてcallテンプレートとしてcountを作成し、GETハンドラを作成します。ソース・タイプPL/SQLを選択します。


テストの準備ができたので、同時に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> 


以上で、Lock Free Reservationの説明は終了です。

ここまで極端なホットスポットはあまり無いとは思います。とはいえ加算と減算に操作を限定できる数値列、例えばページの訪問数やいいねをクリックした数のようなデータがある場合は、適用を検討する価値はあるでしょう。