13.1 読取り一貫性のあるロケータ
Oracle DatabaseのLOBに対する読取り一貫性メカニズムは、その他すべてのスカラー量に対するデータベースの読取りおよび更新のための読取り一貫性メカニズムと同じです。
LOBロケータの場合、読取り一貫性にはいくつかの特別な用途があるため、正しく理解しておく必要があります。次の各項では、読取り一貫性について説明し、互いに関連付けながら参照する必要がある例を示します。
- 読取り一貫性のあるロケータになる、SELECTされたロケータ
読取り一貫性のあるロケータには、SELECT
操作の時点のスナップショット環境が含まれます。 - LOBの更新および読取り一貫性の例
読取り一貫性のあるロケータでは、SELECT
の発生時期に関係なく、同じLOB値が提供されます。次の例は、読取り一貫性とUPDATE
操作の関係を示しています。 - 更新済ロケータを介したLOB更新の例
この項では、ロケータを介したLOB更新について説明します。 - SQL DMLおよびDBMS_LOBを使用したLOBの更新例
次の例では、print_media
表を使用して、CLOB
ロケータをclob_selected
として作成します。 - 同じLOB値を更新するために1つのロケータを使用する例
特定のLOB値の更新にロケータを1つのみ使用する場合は、多くの問題を回避できます。この項では、その詳細について学習します。 - PL/SQL (DBMS_LOB)バインド変数を使用したLOBの更新の例
この項では、PL/SQLバインド変数を使用したLOBの更新について説明します。 - ロケータを使用したLOBの削除の例
この項では、PL/SQLバインド変数を使用したLOBの削除について説明します。 - 読取り一貫性の保証
この項のスクリプトを使用すると、NOLOGGING
またはFILESYSTEM_LIKE_LOGGING
LOBを持つ表のホット・バックアップを取得でき、読取り非一貫性なしでリカバリ・ポイントが既知であることを確認できます。
関連項目:
-
読取り一貫性の一般的な情報は、Oracle Database概要を参照してください
親トピック: 高度な設計時の考慮事項
13.1.1 読取り一貫性のあるロケータになる、SELECTされたロケータ
読取り一貫性のあるロケータには、SELECT
操作の実行時点のスナップショット環境が含まれます。
FOR
UPDATE
句の有無にかかわらず、SELECTされたロケータは読取り一貫性のあるロケータとなり、LOB値がそのロケータによって更新されるまでは読取り一貫性のあるロケータとして存在します。
これには複雑な意味があります。たとえば、SELECT
操作によって読取り一貫性のあるロケータ(L1
)を作成したとします。L1
によって永続LOB値を読み取るときは、次のことに注意してください。
-
SELECT
文にFOR
UPDATE
が含まれていても、SELECT
文実行時点のLOBが読み取られます。 -
同じトランザクションの別のロケータ(
L2
)によってLOB値が更新されても、L1
ではL2
の更新が認識されません。 -
L1
では、別のトランザクションによってLOBにコミットされた更新も認識されません。 -
読取り一貫性のあるロケータ
L1
が別のロケータL2
にコピーされた場合(たとえば、2つのロケータ変数のPL/SQL割当てL2:= L1
によって)、L2
はL1
と同様に読取り一貫性のあるロケータとなり、読み取られるデータはL1
に対するSELECT
実行時点のデータとなります。
複数のロケータが存在していることを利用して、変化するLOB値のそれぞれの値にアクセスできます。ただし、その場合は、どのロケータでどの値にアクセスしているかを常に理解しておく必要があります。
親トピック: 読取り一貫性のあるロケータ
13.1.2 LOBの更新および読取り一貫性の例
読取り一貫性のあるロケータでは、SELECT
実行時期に関係なく同じLOB値が提供されます。次の例は、読取り一貫性とUPDATE
操作の関係を示しています。
print_media
表とPL/SQLを使用して、clob_selected
、clob_update
およびclob_copied
の3つのCLOB
インスタンスをロケータとして作成します。
次のコード例では、t1
からt6
が次のように処理されます。
-
最初の
SELECT
INTO
の実行時(t1
)に、ad_sourcetext
内の値がロケータclob_selected
に対応付けられます。 -
次の操作(
t2
)で、ad_sourcetext
内の値がロケータclob_updated
に対応付けられます。t1
とt2
の間ではad_sourcetext
の値が変わらないため、clob_selected
およびclob_updated
の両方のロケータは、異なる時点でのスナップショットを反映していても、同じ値を持つ読取り一貫性のあるロケータとなります。 -
3つ目の操作(
t3
)では、clob_selected
の値がclob_copied
にコピーされます。この時点で、3つのロケータが同じ値になります。例では、一連のDBMS_LOB
.READ()
コールがこれを示しています。 -
t4
で、プログラムはDBMS_LOB
.WRITE()
を使用してclob_updated
内の値を変更します。DBMS_LOB
.READ()
が新しい値を示します。 -
ただし、
clob_selected
を介した値のDBMS_LOB
.READ()
は(t5
)、これが読取り一貫性のあるロケータで、SELECT
の実行時と同じ値が引き続き参照されることを示します。 -
同様に、
clob_copied
を介した値のDBMS_LOB
.READ()
は(t6
)、これが読取り一貫性のあるロケータで、clob_selected
と同じ値が引き続き参照されることを示します。
例13-1
INSERT INTO print_media VALUES (2056, 20020, EMPTY_BLOB(), 'abcd', EMPTY_CLOB(), EMPTY_CLOB(), NULL, NULL, NULL, NULL); COMMIT; DECLARE num_var INTEGER; clob_selected CLOB; clob_updated CLOB; clob_copied CLOB; read_amount INTEGER; read_offset INTEGER; write_amount INTEGER; write_offset INTEGER; buffer VARCHAR2(20); BEGIN -- At time t1: SELECT ad_sourcetext INTO clob_selected FROM Print_media WHERE ad_id = 20020; -- At time t2: SELECT ad_sourcetext INTO clob_updated FROM Print_media WHERE ad_id = 20020 FOR UPDATE; -- At time t3: clob_copied := clob_selected; -- After the assignment, both the clob_copied and the -- clob_selected have the same snapshot as of the point in time -- of the SELECT into clob_selected -- Reading from the clob_selected and the clob_copied does -- return the same LOB value. clob_updated also sees the same -- LOB value as of its select: read_amount := 10; read_offset := 1; DBMS_LOB.READ(clob_selected, read_amount, read_offset, buffer); DBMS_OUTPUT.PUT_LINE('clob_selected value: ' || buffer); -- Produces the output 'abcd' read_amount := 10; DBMS_LOB.READ(clob_copied, read_amount, read_offset, buffer); DBMS_OUTPUT.PUT_LINE('clob_copied value: ' || buffer); -- Produces the output 'abcd' read_amount := 10; DBMS_LOB.READ(clob_updated, read_amount, read_offset, buffer); DBMS_OUTPUT.PUT_LINE('clob_updated value: ' || buffer); -- Produces the output 'abcd' -- At time t4: write_amount := 3; write_offset := 5; buffer := 'efg'; DBMS_LOB.WRITE(clob_updated, write_amount, write_offset, buffer); read_amount := 10; DBMS_LOB.READ(clob_updated, read_amount, read_offset, buffer); DBMS_OUTPUT.PUT_LINE('clob_updated value: ' || buffer); -- Produces the output 'abcdefg' -- At time t5: read_amount := 10; DBMS_LOB.READ(clob_selected, read_amount, read_offset, buffer); DBMS_OUTPUT.PUT_LINE('clob_selected value: ' || buffer); -- Produces the output 'abcd' -- At time t6: read_amount := 10; DBMS_LOB.READ(clob_copied, read_amount, read_offset, buffer); DBMS_OUTPUT.PUT_LINE('clob_copied value: ' || buffer); -- Produces the output 'abcd' END; /
親トピック: 読取り一貫性のあるロケータ
13.1.3 更新済ロケータを介したLOB更新の例
この項では、ロケータを介したLOBの更新について学習します。
LOBロケータ(L1
)を介して永続LOBの値を更新する場合、現在のスナップショット環境が含まれるようL1
が更新されます。
このスナップショットは、ロケータL1
を介してLOB値に対する操作が完了した時点のものです。このため、L1
は更新済ロケータと呼ばれます。この操作によって、LOB値に対して行った変更を、同じロケータL1
による次の読取り時に参照できます。
ノート:
LOB値を読み取ることのみのためにロケータが使用される場合、ロケータのスナップショット環境は更新されません。更新されるのは、PL/SQL DBMS_LOB
パッケージまたはOCI LOB APIを使用して、ロケータを介してLOB値を変更した場合のみです。
別のトランザクションによってコミットされた更新は、そのトランザクションがコミット読取りトランザクションであり、他のトランザクションのコミット後にL1を使用してLOB値を更新する場合のみに、L1によって認識されます。
ノート:
永続LOBの値を更新すると、最新のLOB値が常に変更されます。
OCI LOB APIやPL/SQL DBMS_LOB
パッケージなどの使用可能なメソッドによって永続LOBの値を更新することは、LOB値を更新して、新しいLOB値を参照するロケータを再選択することになります。
親トピック: 読取り一貫性のあるロケータ
13.1.4 SQL DMLおよびDBMS_LOBを使用したLOBの更新例
次の例では、print_media
表を使用し、CLOB
ロケータがclob_selected
として作成されます。
この例では、t1
からt3
が次のように処理されます。
-
最初の
SELECT
INTO
の実行時(t1
)に、ad_sourcetext
内の値がロケータclob_selected
に対応付けられます。 -
次の操作(
t2
)では、ロケータclob_selected
に影響を与えずに、SQL
UPDATE
文を介してad_sourcetext
内の値が変更されます。ロケータは元のSELECT
時点でのLOB値を参照します。つまり、ロケータはSQLUPDATE
文によって実行された更新を認識しません。例では、後続のDBMS_LOB
.READ()
コールがこれを示しています。 -
3つ目の操作(
t3
)では、LOB値が再選択されロケータclob_selected
に挿入されます。これによって、ロケータは最新のスナップショット環境に更新され、先のSQLUPDATE
文によって行われた変更を認識できるようになります。このため、次のDBMS_LOB
.READ()
では、LOB値が空である(データがない)ためエラーが戻されます。
INSERT INTO Print_media VALUES (3247, 20010, EMPTY_BLOB(), 'abcd', EMPTY_CLOB(), EMPTY_CLOB(), NULL, NULL, NULL, NULL); COMMIT; DECLARE num_var INTEGER; clob_selected CLOB; read_amount INTEGER; read_offset INTEGER; buffer VARCHAR2(20); BEGIN -- At time t1: SELECT ad_sourcetext INTO clob_selected FROM Print_media WHERE ad_id = 20010; read_amount := 10; read_offset := 1; dbms_lob.read(clob_selected, read_amount, read_offset, buffer); dbms_output.put_line('clob_selected value: ' || buffer); -- Produces the output 'abcd' -- At time t2: UPDATE Print_media SET ad_sourcetext = empty_clob() WHERE ad_id = 20010; -- although the most current LOB value is now empty, -- clob_selected still sees the LOB value as of the point -- in time of the SELECT read_amount := 10; dbms_lob.read(clob_selected, read_amount, read_offset, buffer); dbms_output.put_line('clob_selected value: ' || buffer); -- Produces the output 'abcd' -- At time t3: SELECT ad_sourcetext INTO clob_selected FROM Print_media WHERE ad_id = 20010; -- the SELECT allows clob_selected to see the most current -- LOB value read_amount := 10; dbms_lob.read(clob_selected, read_amount, read_offset, buffer); -- ERROR: ORA-01403: no data found END; /
親トピック: 読取り一貫性のあるロケータ
13.1.5 同じLOB値を更新するために1つのロケータを使用する例
特定のLOB値の更新にはロケータを1つのみ使用することで、多くの問題を回避できます。この項では、その詳細について学習します。
次の例では、表print_media
を使用し、clob_updated
およびclob_copied
の2つのCLOB
をロケータとして作成します。
この例では、t1からt5が次のように処理されます。
-
最初の
SELECT
INTO
の実行時(t1
)に、ad_sourcetext
内の値がロケータclob_updated
に対応付けられます。 -
次の操作(
t2
)では、clob_updated
の値がclob_copied
にコピーされます。この時点では、両方のロケータが同じ値を参照します。例では、一連のDBMS_LOB
.READ()
コールがこれを示しています。 -
t3
で、プログラムはDBMS_LOB
.WRITE()
を使用してclob_updated
内の値を変更します。DBMS_LOB.READ()
が新しい値を示します。 -
ただし、
clob_copied
を介した値のDBMS_LOB
.READ()
は(t4
)、clob_updated
から割り当てられた時点(t2
)のLOBの値を参照しています。 -
clob_updated
がclob_copied
に割り当てられた時点(t5
)で初めて、clob_copied
はclob_updated
による更新があったことを認識します。
INSERT INTO PRINT_MEDIA VALUES (2049, 20030, EMPTY_BLOB(), 'abcd', EMPTY_CLOB(), EMPTY_CLOB(), NULL, NULL, NULL, NULL); COMMIT; DECLARE num_var INTEGER; clob_updated CLOB; clob_copied CLOB; read_amount INTEGER; read_offset INTEGER; write_amount INTEGER; write_offset INTEGER; buffer VARCHAR2(20); BEGIN -- At time t1: SELECT ad_sourcetext INTO clob_updated FROM PRINT_MEDIA WHERE ad_id = 20030 FOR UPDATE; -- At time t2: clob_copied := clob_updated; -- after the assign, clob_copied and clob_updated see the same -- LOB value read_amount := 10; read_offset := 1; dbms_lob.read(clob_updated, read_amount, read_offset, buffer); dbms_output.put_line('clob_updated value: ' || buffer); -- Produces the output 'abcd' read_amount := 10; dbms_lob.read(clob_copied, read_amount, read_offset, buffer); dbms_output.put_line('clob_copied value: ' || buffer); -- Produces the output 'abcd' -- At time t3: write_amount := 3; write_offset := 5; buffer := 'efg'; dbms_lob.write(clob_updated, write_amount, write_offset, buffer); read_amount := 10; dbms_lob.read(clob_updated, read_amount, read_offset, buffer); dbms_output.put_line('clob_updated value: ' || buffer); -- Produces the output 'abcdefg' -- At time t4: read_amount := 10; dbms_lob.read(clob_copied, read_amount, read_offset, buffer); dbms_output.put_line('clob_copied value: ' || buffer); -- Produces the output 'abcd' -- At time t5: clob_copied := clob_updated; read_amount := 10; dbms_lob.read(clob_copied, read_amount, read_offset, buffer); dbms_output.put_line('clob_copied value: ' || buffer); -- Produces the output 'abcdefg' END; /
親トピック: 読取り一貫性のあるロケータ
13.1.6 PL/SQL(DBMS_LOB)バインド変数を使用したLOBの更新の例
この項では、PL/SQLバインド変数を使用したLOBの更新について学習します。
別の永続LOBを更新するためのソースとしてLOBロケータを使用する場合(SQLのINSERT
文またはUPDATE
文、DBMS_LOB
.COPY
ルーチンなど)、ソースLOBロケータ内のスナップショット環境によって、ソースとして使用されるLOB値が決まります。
ソース・ロケータ(たとえばL1
)が読取り一貫性のあるロケータの場合、L1
のSELECT
実行時点のLOB値が使用されます。ソース・ロケータ(たとえばL2
)が更新済ロケータの場合、更新時におけるL2
のスナップショット環境に対応付けられたLOB値が使用されます。
次の例では、clob_selected
、clob_updatedおよびclob_copiedの3つのCLOB
をロケータとして作成します。
この例では、t1
からt5
が次のように処理されます。
-
最初の
SELECT
INTO
の実行時(t1
)に、ad_sourcetext
内の値がロケータclob_updated
に対応付けられます。 -
次の操作(
t2
)では、clob_updated
の値がclob_copied
にコピーされます。この時点では、両方のロケータが同じ値を参照します。 -
この時点で(
t3
)、プログラムはDBMS_LOB
.WRITE()
を使用してclob_updated
内の値を変更します。DBMS_LOB
.READ()
が新しい値を示します。 -
ただし、
clob_copied
を介した値のDBMS_LOB
.READ()
は(t4
)、clob_copied
がclob_updated
による変更を参照しないことを示します。 -
このため(
t5
の時点で)、clob_copied
をINSERT
文の値のソースとして使用する場合、clob_copied
と対応付けられた値が挿入されます(clob_updated
による新規の変更は反映されません)。これは、その後の、挿入された直後の値に対するDBMS_LOB
.READ()
によってわかります。
INSERT INTO PRINT_MEDIA VALUES (2056, 20020, EMPTY_BLOB(), 'abcd', EMPTY_CLOB(), EMPTY_CLOB(), NULL, NULL, NULL, NULL); COMMIT; DECLARE num_var INTEGER; clob_selected CLOB; clob_updated CLOB; clob_copied CLOB; read_amount INTEGER; read_offset INTEGER; write_amount INTEGER; write_offset INTEGER; buffer VARCHAR2(20); BEGIN -- At time t1: SELECT ad_sourcetext INTO clob_updated FROM PRINT_MEDIA WHERE ad_id = 20020 FOR UPDATE; read_amount := 10; read_offset := 1; dbms_lob.read(clob_updated, read_amount, read_offset, buffer); dbms_output.put_line('clob_updated value: ' || buffer); -- Produces the output 'abcd' -- At time t2: clob_copied := clob_updated; -- At time t3: write_amount := 3; write_offset := 5; buffer := 'efg'; dbms_lob.write(clob_updated, write_amount, write_offset, buffer); read_amount := 10; dbms_lob.read(clob_updated, read_amount, read_offset, buffer); dbms_output.put_line('clob_updated value: ' || buffer); -- Produces the output 'abcdefg' -- note that clob_copied does not see the write made before -- clob_updated -- At time t4: read_amount := 10; dbms_lob.read(clob_copied, read_amount, read_offset, buffer); dbms_output.put_line('clob_copied value: ' || buffer); -- Produces the output 'abcd' -- At time t5: -- the insert uses clob_copied view of the LOB value which does -- not include clob_updated changes INSERT INTO PRINT_MEDIA VALUES (2056, 20022, EMPTY_BLOB(), clob_copied, EMPTY_CLOB(), EMPTY_CLOB(), NULL, NULL, NULL, NULL) RETURNING ad_sourcetext INTO clob_selected; read_amount := 10; dbms_lob.read(clob_selected, read_amount, read_offset, buffer); dbms_output.put_line('clob_selected value: ' || buffer); -- Produces the output 'abcd' END; /
親トピック: 読取り一貫性のあるロケータ
13.1.7 ロケータを使用したLOBの削除の例
この項では、PL/SQLバインド変数を使用したLOBの削除について学習します。
次の例では、特定の時点で選択されたロケータを介したLOBコンテンツを、同じトランザクション内でそのLOBが削除されている場合でも使用可能であることを示します。
次の例では、print_media
表を使用し、clob_selected
およびclob_copied
という2つのCLOBをロケータとして作成します。
この例では、t1
からt3
が次のように処理されます。
- 最初の
SELECT
INTO
の実行時(t1
)に、ad_id
の値が20020であるad_sourcetext
の値が、ロケータclob_selected
に対応付けられます。ad_id
の値が20021であるad_sourcetext
の値は、ロケータclob_copied
に関連付けられます。 - 2つ目の操作(
t2
)では、ad_id
の値が20020である行が削除されます。ただし、clob_selected
を介した値のDBMS_LOB.READ()
は(t1
)、これが読取り一貫性のあるロケータであり、SELECTの実行時と同じ値が引き続き参照されることを示します。 - 3つ目の操作(
t3
)では、clob_selected
を介して読み取られたLOBデータがLOBclob_copied
にコピーされます。clob_selected
およびclob_copied
を介した値のDBMS_LOB.READ()
はこれと同じになり、clob_selected
のSELECT
の実行時と同じ値を参照します。
INSERT INTO PRINT_MEDIA VALUES (2056, 20020, EMPTY_BLOB(), 'abcd', EMPTY_CLOB(), EMPTY_CLOB(), NULL, NULL, NULL, NULL); INSERT INTO PRINT_MEDIA VALUES (2057, 20021, EMPTY_BLOB(), 'cdef', EMPTY_CLOB(), EMPTY_CLOB(), NULL, NULL, NULL, NULL); DECLARE clob_selected CLOB; clob_copied CLOB; buffer VARCHAR2(20); read_amount INTEGER := 20; read_offset INTEGER := 1; BEGIN -- At time t1: SELECT ad_sourcetext INTO clob_selected FROM PRINT_MEDIA WHERE ad_id = 20020 FOR UPDATE; SELECT ad_sourcetext INTO clob_copied FROM PRINT_MEDIA WHERE ad_id = 20021 FOR UPDATE; dbms_lob.read(clob_selected, read_amount, read_offset,buffer); dbms_output.put_line(buffer); -- Produces the output 'abcd' dbms_lob.read(clob_copied, read_amount, read_offset,buffer); dbms_output.put_line(buffer); -- Produces the output 'cdef' -- At time t2: Delete the CLOB associated with clob_selected DELETE FROM PRINT_MEDIA WHERE ad_id = 20020; dbms_lob.read(clob_selected, read_amount, read_offset,buffer); dbms_output.put_line(buffer); -- Produces the output 'abcd' -- At time t3: -- Copy using clob_selected dbms_lob.copy(clob_copied, clob_selected, 4000, 1, 1); dbms_lob.read(clob_copied, read_amount, read_offset,buffer); dbms_output.put_line(buffer); -- Produces the output 'abcd' END; /
親トピック: 読取り一貫性のあるロケータ
13.1.8 読取り一貫性の保証
この項のスクリプトを使用すると、NOLOGGING
またはFILESYSTEM_LIKE_LOGGING
LOBを持つ表のホット・バックアップを取得でき、読取り非一貫性なしでリカバリ・ポイントが既知であることを確認できます。
ALTER DATABASE FORCE LOGGING; SELECT CHECKPOINT_CHANGE# FROM V$DATABASE; --Start SCN
SCN(システム変更番号)は、トランザクションがコミットされた時点のデータベースのバージョンを定義するスタンプです。
バックアップを実行します。
次のスクリプトを実行します。
ALTER SYSTEM CHECKPOINT GLOBAL; SELECT CHECKPOINT_CHANGE# FROM V$DATABASE; --End SCN ALTER DATABASE NO FORCE LOGGING;
データベースで生成されたアーカイブ・ログをバックアップします。少なくとも、開始SCNと終了SCN(両方のSCN時点を含む)の間のアーカイブ・ログはバックアップする必要があります。
読取り非一貫性のない時点までリストアするため、不完全なリカバリの時点として終了SCNまでリストアします。終了SCNより後のSCNにリカバリを実行すると、NOLOGGING
LOBで読取り非一貫性が発生する可能性があります。
SecureFilesでは、メディア・リカバリ中に読取り非一貫性が検出されると、データベースにより一貫性のないブロックがホールとして処理され、BLOB
に0
が、CLOB
に充填文字が格納されます。
親トピック: 読取り一貫性のあるロケータ