この記事はAndy RivenesによるMemoptimized Rowstore – Fast Ingest Updatesを日本語に翻訳したものです。

2023年10月8日


Memoptimized Rowstore 高速収集機能は、Oracle Database 19cで導入され、2019年4月にこのブログで書きました。 それ以降、高速収集機能にいくつか更新があったので、共有したいと思います。LOBsと暗号化のサポートは、Oracle Database 19.16および21.3から追加されました。

簡単におさらいすると、Memoptimized Rowstore 高速収集は、大規模なデータロードを置き換えることを目的とした機能ではありません。 そのような処理は、ダイレクト・ロード・パスを利用するのが最適です。 高速収集機能は、INSERTのトランザクション自体のオーバーヘッドを削減し、全体としては重要な値を持つが必ずしも完全なACID要件を必要としない大量のデータを生成するアプリケーションをサポートすることを目的としています。 これはラージ・プールに割り当てられたメモリーにデータを直接INSERTし、非同期にバックグランド・プロセスによってディスクへ書き込むことで実現しています。 INSERTはUNDOやREDOによって保護されていないため、ロールバックすることはできません。また、データがディスクに書き込まれる前にインスタンスがダウンした場合、アプリケーションによって再度INSERTする必要があります。 このアーキテクチャは、収集処理能力を最大化するために作成されたため、Oracleの通常のトランザクション処理はバイパスされます。 データがディスクに書き込まれたことを確認するための特別な書き込みAPIがあります。この後、いくつかの例でAPIを使用します。

高速収集機能は特殊な性質なため、サポートされるデータ・タイプに多くの 多くの制限がありました。 2つの大きな制限として、LOBsと暗号化がありました。 Oracle Database 19.16と21.3以降ではこれらの制限はなくなりました。どのように機能するかを説明するために、Oracle Database 19.16を使用した例をしまします。

前回のブログと同じテーブル構造を使用して、TEST_COL列をSecureFilesのCLOBに変更し、高速収集のテストをしてみます。 ラージ・オブジェクト(LOB)のサポートは、インラインLOBのみである点にも注意してください。

create table test_SF_fi (
  id number primary key,
  test_col CLOB )
  segment creation immediate
  tablespace TS_DATA
  LOB(test_col) STORE AS SECUREFILE(
    ENABLE STORAGE IN ROW
    NOCOMPRESS
    CACHE
  )
  memoptimize for write;

テーブルが作成されたら、MEMOPTIMIZE_WRITEヒントを使用して2行高速収集INSERTします。

SQL> insert /*+ memoptimize_write */ into test_SF_fi values (1, 'test');

1 row created.

SQL> insert /*+ memoptimize_write */ into test_SF_fi values (2, 'test');

1 row created.

SQL> select /*+ seqid session rows written to large pool */ to_number(dbms_memoptimize.GET_WRITE_HWM_SEQID) from dual;

TO_NUMBER(DBMS_MEMOPTIMIZE.GET_WRITE_HWM_SEQID)
-----------------------------------------------
                                  1794603124645

SQL> select /*+ seqid rows written to disk */ to_number(dbms_memoptimize.GET_APPLY_HWM_SEQID) from dual;

TO_NUMBER(DBMS_MEMOPTIMIZE.GET_APPLY_HWM_SEQID)
-----------------------------------------------
                                              0

SQL> exec dbms_memoptimize.write_end;

PL/SQL procedure successfully completed.

SQL> exec sys.dbms_session.sleep(10);

PL/SQL procedure successfully completed.

SQL> select /*+ seqid session rows written to large pool  */ to_number(dbms_memoptimize.GET_WRITE_HWM_SEQID) from dual;

TO_NUMBER(DBMS_MEMOPTIMIZE.GET_WRITE_HWM_SEQID)
-----------------------------------------------
                                  1794603124645

SQL> select /*+ seqid rows written to disk  */ to_number(dbms_memoptimize.GET_APPLY_HWM_SEQID) from dual;

TO_NUMBER(DBMS_MEMOPTIMIZE.GET_APPLY_HWM_SEQID)
-----------------------------------------------
                                  1794612887883

SQL>
SQL> select * from test_SF_fi;

              ID TEST_COL
---------------- ------------------------------------------
               1 test
               2 test

SQL>

この例で注意すべき点がいくつかあります。高速収集ではコミットがサポートされていないため、コミットは発行していません。MEMOPTIMIZE_WRITEヒントの使用にも注意してください。

また、挿入されたデータがディスクに永続化されていることを確認するために、DBMS_MEMOPTIMIZE書き込みAPI呼び出しも追加しました:

  1. 最初のDBMS_MEMOPTIMIZE.GET_WRITE_HWM_SEQIDの呼び出しにより、ラージ・プールのメモリに挿入された行に関連付けられた順序がわかります。DBMS_MEMOPTIMIZE.GET_APPLY_HWM_SEQIDを呼び出すとディスクに書き込まれる行の最大順序IDがわかります。最初の順序IDが2番目の順序IDより大きいことに注目してください。インスタンスが開始されてから、ディスクに書き込みが行われていないので、実際には値は0です。
  2. 待ちたくなく、データベースへの書き込みをすぐに開始するようにしたかったので、DBMS_MEMOPTIMIZE.WRITE_ENDをコールした。これを行く必要はありません。ただ私はせっかちでした。
  3. 次に、Sleepコマンドを発行して、データベースがデータをディスクに書き込む時間を与えました。
  4. 順序IDを再度呼び出して、データが書き込まれたことを確認しました。このステップでは、適用ハイウォーター・マーク(HWM)順序が書き込みハイウォーター・マーク(HWM)順序より大きいことがわかります。
  5. 最後に、データが存在するかどうか検索して確認しました。究極の執念のテスト

仕組みが少し分かりにくい場合は、DBMS_MEMOPTIMIZEパッケージの説明をPL/SQL Packages and Types Referenceに記載しています。

これで高速収集がLOBをサポートしていることがわかりました。暗号化についてはどうですか?次の例は、暗号化と高速収集の設定をする必要があるため、少々複雑になります。暗号化は表領域暗号化、行レベル暗号化、そしてSecufeFile暗号化をサポートしています。 私は簡単に表領域暗号化を設定しました。表領域暗号化に明るくない場合には、Advanced Security Guideを参照し、その仕組みを学ぶことができます。

次に、データベースで暗号化を設定し、キーストアを開いた後に使用した表領域の定義を示します。

CREATE TABLESPACE encrypted_ts
DATAFILE SIZE 128K
AUTOEXTEND ON NEXT 64K
ENCRYPTION USING 'AES256'
DEFAULT STORAGE(ENCRYPT);

この例では、最初のブログと同じシンプルなテーブル定義を利用します。 ただし、暗号化された表領域に切り替えていることに注意してください。:

create table test_encrypt_fi (
id number primary key,
test_col varchar2(15) )
segment creation immediate
tablespace encrypted_ts
memoptimize for write;

そして、テストします:

SQL> insert /*+ memoptimize_write */ into test_encrypt_fi values (1, 'test');

1 row created.

SQL> insert /*+ memoptimize_write */ into test_encrypt_fi values (2, 'test');

1 row created.

SQL> select /*+ seqid session rows written to large pool  */ to_number(dbms_memoptimize.GET_WRITE_HWM_SEQID) from dual;

TO_NUMBER(DBMS_MEMOPTIMIZE.GET_WRITE_HWM_SEQID)
-----------------------------------------------
                  2308680139702

SQL> select /*+ seqid rows written to disk  */ to_number(dbms_memoptimize.GET_APPLY_HWM_SEQID) from dual;

TO_NUMBER(DBMS_MEMOPTIMIZE.GET_APPLY_HWM_SEQID)
-----------------------------------------------
                  2308680136692

SQL> exec dbms_memoptimize.write_end;

PL/SQL procedure successfully completed.

SQL> exec sys.dbms_session.sleep(10);

PL/SQL procedure successfully completed.

SQL> select /*+ seqid session rows written to large pool  */ to_number(dbms_memoptimize.GET_WRITE_HWM_SEQID) from dual;

TO_NUMBER(DBMS_MEMOPTIMIZE.GET_WRITE_HWM_SEQID)
-----------------------------------------------
                  2308680139702

SQL> select /*+ seqid rows written to disk  */ to_number(dbms_memoptimize.GET_APPLY_HWM_SEQID) from dual;

TO_NUMBER(DBMS_MEMOPTIMIZE.GET_APPLY_HWM_SEQID)
-----------------------------------------------
                  2308689712017

SQL> select * from test_encrypt_fi;

          ID TEST_COL
---------------- ---------------
           1 test
           2 test

SQL>

幸運なことに、同様な肯定的な結果が得られました。 制約違反など何らかの理由で行が挿入されなかった場合、アプリケーションの挿入は失敗しない。索引操作と制約チェックは、データがラージ・プールの高速収集エリアからディスクに書き込まれるときにのみ実施されることを思い出してください。これは、行が確かに書き込まれたことを検証するために、書き込みと適用順序IDを使用したチェックをコード化することが重要であるもう1つの理由です。

この投稿がMemoptimized Rowstore高速収集機能に追加された新しいLOBと暗号化のサポートを明確にする一助となれば幸いです。