※ 本記事は、Gregg Christmanによる”New Lock-Free Reservation Capability with Oracle Database 23ai“を翻訳したものです。

2024年9月9日


ロックフリー予約では、列値の加算または減算時に、コミットされていない更新によってブロックされることなく、数値の列値で複数の同時更新を続行できます。これには、借方および貸方トランザクションに基づく銀行口座残高、在庫管理、サプライ・チェーン、財務または投資銀行、在庫、出張および交際などのアプリケーションが含まれます。

これらのアプリケーションでは、多数のトランザクションが数値データに同時にアクセスする可能性が高く、多くの場合、アプリケーションはそのようなデータを継続的に読み取りまたは更新するため、このデータは”ホット”リソースとして識別されます。マイクロサービス・アプリケーションなどの長時間実行トランザクションでは、リソースは長期間ロックされたままになり、ホット・リソースになる可能性があります。長期的なリソース・ロックによって同時実行性が制限され、多くのビジネス・アプリケーションでホット・データへの同時アクセスがブロックされると、パフォーマンスに重大な影響が生じ、ユーザー・エクスペリエンスとスループットが低下する可能性があります。

更新時の従来のロックメカニズムを回避することで、ロックフリー予約は、数値データへの頻繁な同時更新が存在する場合にブロックを減らすことで、ユーザー・エクスペリエンスを大幅に向上させることができます。

並行性の一般的な処理方法– 例

以前のリリースでは、行の列値を加算または減算して更新すると、その行に対する他のすべての更新は、トランザクションがコミットされるまでブロックされます。

たとえば、顧客のショッピング・カートには販売前にアイテムがカートに追加されているとします。この場合、顧客はスマート・ウォッチを購入したいと考え、ショッピングカートに入れましたが、本当に購入を完了させるかどうかはまだ決めていません。

このショッピング・アプリケーションは、ユーザーが商品をカートに入れた時、様々な状態で複数のトランザクションを処理できますが、ロックフリー予約がないと、顧客が購入を検討している間は行がロックされます。

行ロックのため、店舗に残っている特定のアイテムのウォッチは、(ある程度の時間)他のバイヤーが購入することができず、まだ購入を待っている顧客に販売することができません。購入を待っている顧客は、他のサイトを見て購入するかもしれませんし、ソーシャル・メディアにユーザー・エクスペリエンスに関するコメントを投稿するかもしれません。

ロックフリー予約が役立つ方法

ロックフリー予約では、かわりに、更新を続行できる条件を指定することで、トランザクションが同じ予約可能列に対して同時に加算または減算されるようにできます。これを行うには、数値列がRESERVABLE列であることを指定し、列に対してCHECK制約を作成して、トランザクションで予約の実行を許可する前に十分な数の品目が使用可能であることを確認します。

予約可能列の更新によって行がロックされないため、別のトランザクションで同じ行の非予約可能列が同時に更新されないため、スループットの向上も実現できます。

予約可能列、予約ジャーナルおよびCHECK制約の概要

ロックフリー予約機能はデフォルトで有効になっています。lockfree_reservationという名前のロックフリー予約パラメータはPDBレベルで指定され、このシステム・レベル・パラメータのデフォルト値はONです。次のパラメータを使用して、PDBごとにロックフリー予約機能を無効にできます:

ALTER SYSTEM SET lockfree_reservation = OFF;

ロックフリー予約を使用するには、表を作成またはALTERするときにRESERVABLEキーワードを使用してRESERVABLE列を宣言します。数値データ型の列では、ロックフリー予約の同時実行性が提供されます。

次に例を示します:

CREATE TABLE Account( ID NUMBER PRIMARY KEY, Name VARCHAR2(10), Balance NUMBER RESERVABLE CONSTRAINT minimum_balance CHECK (Balance >= 50))

潜在的な予約可能列を特定するには、同時実行性の向上による利点がある数値の集計データを含むホット・リソースを探します。

RESERVABLE列を含む表を作成すると、関連付けられた予約ジャーナル表が自動的に作成されます。予約ジャーナル表は、ユーザー表と同じユーザー・スキーマおよびユーザー表と同じ表領域に作成されます。

トランザクションが予約可能列の更新操作を発行すると、予約可能更新は予約ジャーナルのロックフリー予約として追跡されます。トランザクション更新では、(予約可能な更新がある)行はロックされませんが、行の予約可能列をデルタ量分で変更(加算または減算)することを示します。

変更量は予約および約束されているため、他の未コミットおよび同時トランザクションを待機せずにトランザクションを続行できます。予約により、他の同時トランザクションで同じ行に予約可能な更新を発行できます。

列レベルまたは表レベルのCHECK制約に予約可能な列を含めることができます。CHECK制約を使用すると、表内の各行で満たす必要がある条件を指定できます。

次に例を示します:

CREATE TABLE Account( ID NUMBER PRIMARY KEY, Name VARCHAR2(10), Balance NUMBER reservable, Earmark NUMBER, Limit NUMBER, CONSTRAINT minimum_balance CHECK (Balance + Limit – Earmark >= 0));

制約のない予約可能な列を定義することもできます。このような予約可能な列では、すべてのロックフリー予約が成功します。同時更新は、行をロックせずにパラレルに続行されます。

ユース・ケースの例

次の例では、予約可能な列qty_on_handおよびCHECK制約を持つ表インベントリを作成します。

CREATE TABLE inventory
  (item_id NUMBER CONSTRAINT inv_pk PRIMARY KEY,
   item_display_name VARCHAR2(100) NOT NULL,
   item_desc VARCHAR2(2000),
   qty_on_hand NUMBER RESERVABLE CONSTRAINT qty_ck CHECK (qty_on_hand >= 0),
   shelf_capacity NUMBER NOT NULL, CONSTRAINT shelf_ck CHECK (qty_on_hand <=  
   shelf_capacity));

qty_on_handのCHECK制約では、qty_on_handの更新を続行するために、在庫にゼロ個以上のアイテムが存在し、このアイテムの棚容量を超えないように指定します。

この例では、いくつかの値を挿入します。

INSERT INTO inventory VALUES (123, ‘Milk’, ‘Lowfat 2%’, 100, 120);
INSERT INTO inventory VALUES (456, ‘Bread’, ‘Multigrain’, 50, 100);
INSERT INTO inventory VALUES (789, ‘Eggs’, ‘Organic’, 50, 75);

INSERTS後のInventory表。

ITEM_ID ITEM_DISPLAY_NAME         ITEM_DESC            QTY_ON_HAND    SHELF_CAPACITY
———– ———————————– ———————– ———————– ———————
123         Milk                                        Lowfat 2%             100                         120
456         Bread                                     Multigrain              50                           100
789         Eggs                                        Organic                  50                           75

次に、RESERVABLE列に対して複数の同時UPDATEを実行します。

Transaction 1: UPDATE inventory SET qty_on_hand = qty_on_hand – 10 WHERE item_id = 123;
Transaction 2: UPDATE inventory SET qty_on_hand = qty_on_hand + 20 WHERE item_id = 123;
Transaction 3: UPDATE inventory SET qty_on_hand = qty_on_hand – 30 WHERE item_id = 123;

この例では、CHECK制約に違反していないため、同時トランザクションはロックフリー予約の実行に成功しています。

UPDATEトランザクションのコミット。

Transaction 2: commit;
Transaction 3: commit;
Transaction 1: commit;

この例では、トランザクションのコミットの順序が2、3、1であることに注意してください。これは、コミットまでロック取得を遅延させるロックフリー予約のため、UPDATEトランザクションの準備ができた時点でコミットできます。これをロックフリー予約のない同じ操作と比較します。トランザクション2は、トランザクション1が行ロックを解放するまで待機してから更新してからコミットし、同様にトランザクション3はトランザクション2のコミットを待機する必要があります。

更新の発行時に承認された保留中のロックフリー予約は、後でトランザクションのコミット時にそのような制約に違反する可能性があります。これは、現在の値がCHECK制約に違反するように、予約が行われた後、表レベル制約の非予約可能列が更新された場合に発生する可能性があります。

制約に違反した場合は、トランザクションを終了する必要があります。ただし、表レベル制約の非予約可能列は、通常、変更頻度が非常に低いしきい値です。

ロックフリー予約のメリット

トランザクションの原子性、一貫性および永続性を維持しながら、独立性を減じて同時実行性が向上すると、アプリケーションでメリットが得られます。

同時実行性の向上

  • 競合する数値による更新の同時実行性が向上します。
  • ロックフリー予約は、予約可能列で、並行トランザクションは、行をロックせずに予約可能列の値から金額を予約できます。
  • トランザクション期間のロックではなく、非常に短い期間ロックを保持します。

OLTPのスケーラビリティの向上

  • 同時予約の混在で新しい予約を許可できる場合は、ロックフリー予約リクエストが適用されます。
  • 実際の行変更およびロック取得は、トランザクションのコミット時に延期されます。
  • 勘定科目残高、アイテム在庫など、競合する数値の高いアプリケーションでOLTPのスケーリングを支援します。

ユーザー・エクスペリエンスの向上

  • ホット行の予約可能列に対する同時更新がブロックされずに同時に続行できるため、ユーザー・エクスペリエンスが向上します。
  • 在庫管理、サプライチェーン、財務または投資のバンキング、在庫、出張、エンターテイメントなどを提供するアプリケーションで有益であり、多くの場合”ホット”な数値集計データを操作します。

まとめ

ロックフリー予約では、ホット・リソースによって同時実行性のボトルネックは発生しません。在庫管理、銀行、ショッピング・カート、請求と支払、小売、サプライ・チェーン、チケット発行、予約管理などのアプリケーションには、この機能の利点があります。

詳細および使用方法の詳細および例は、Oracleドキュメントを参照してください[こちら]。