OracleDataReaderオブジェクトからのデータの取得
OracleCommandオブジェクトのExecuteReaderメソッドは、OracleDataReaderオブジェクトを戻します。このオブジェクトは、読取り専用および順方向専用の結果セットです。
この項では、OracleDataReaderオブジェクトに関する次の情報を示します。
OracleDataReader型指定アクセッサ
OracleDataReaderクラスは、2つのタイプの型指定アクセッサを提供します。
.NETタイプのアクセッサ
表3-15には、ODP.NETがサポートするすべてのOracleデータベースのネイティブ・タイプと、それらに対応した、Oracleネイティブ・タイプを表す.NETタイプがリストされています。Oracleネイティブ・タイプを表すために複数の.NETタイプが使用される場合、最初の.NETタイプ・エントリは、Oracleネイティブ・タイプを最も適切に表します。3列目は、.NETタイプとして取得されるOracleネイティブ・タイプに対して起動される有効な型指定アクセッサを示します。無効な型指定アクセッサが列に使用された場合、InvalidCastExceptionがスローされます。Oracleネイティブ・データ型は、データベースのバージョンに依存します。このため、Oracle Databaseの以前のバージョンでは使用できないデータ型もあります。
表3-15 .NETタイプのアクセッサ
| Oracleネイティブ・データ型 | .NETタイプ | 型指定アクセッサ |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OracleDataReaderオブジェクトの一部のメソッドおよびプロパティでは、列の精度とスケールに基づいて、ODP.NETでNUMBER列を.NETタイプにマップする必要があります。これらのメンバーは、次のとおりです。
-
Itemプロパティ -
GetFieldTypeメソッド -
GetValueメソッド -
GetValuesメソッド
ODP.NETは、次の.NETタイプを順に検証して、列の値の範囲全体を表すリストの最初の.NETタイプを選択することで、適切な.NETタイプを決定します。
-
System.Byte -
System.Int16 -
System.Int32 -
System.Int64 -
System.Single -
System.Double -
System.Decimal
列の値の範囲全体を表す.NETタイプが存在しない場合、列値をSystem.Decimalタイプとして表そうとします。列の値をSystem.Decimalとして表せない場合、例外が発生します。
たとえば、2つの列をNUMBER(4,0)およびNUMBER(10,2)として定義してみます。列の値の範囲全体を表す前のリストでは、最初の.NETタイプはそれぞれSystem.Int16とSystem.Doubleです。次に、列をNUMBER(20,10)として定義してみます。この場合、列の値の範囲全体を表す.NETタイプが存在しないため、列の値をSystem.Decimalタイプとして戻そうとします。列の値をSystem.Decimalタイプとして表せない場合、例外が発生します。
OracleDataAdapterのFillメソッドは、OracleDataReaderオブジェクトを使用して、.NETタイプのDataTableまたはDataSetを移入あるいはリフレッシュします。その結果、DataTableまたはDataSetのNUMBER列を表すために使用される.NETタイプも、その列の精度とスケールに依存します。
ODP.NETタイプのアクセッサ
ODP.NETは、データベースのデータ型をネイティブに表すプロバイダ固有のタイプを公開します。これらのODP.NETタイプにより、対応する.NETタイプよりもパフォーマンスおよび機能性が上回る機能が提供される場合があります。ODP.NETタイプは、それぞれの型指定アクセッサをコールすることで、OracleDataReaderオブジェクトから取得できます。
表3-16には、ODP.NETがOracleネイティブ・タイプのODP.NETタイプを取得する際に使用する有効なタイプのアクセッサがリストされています。
表3-16 ODP.NETタイプのアクセッサ
| Oracleネイティブ・データ型 | ODP.NETタイプ | 型指定アクセッサ |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OracleRef |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
関連項目:
すべてのODP.NETタイプのリストは、ODP.NETタイプの概要を参照してください
LONGおよびLONG RAWデータの取得
ODP.NETは、OracleDataReaderオブジェクトでReadメソッドを起動中に、データベースから行をフェッチおよびキャッシュします。この操作により取得されるLONGおよびLONG RAW列データの量は、InitialLONGFetchSizeにより決定されます。InitialLONGFetchSizeが、0、0より大きな値および-1に設定されている場合の動作の違いは、次の各項で説明します。
ノート:
ODP.NETでは、CommandBehavior.SequentialAccess列挙値はサポートされていません。このため、LONGおよびLONG RAWデータはランダムにフェッチできます。
InitialLONGFetchSizeを0(ゼロ)または0(ゼロ)より大きな値に設定
OracleDataReaderオブジェクトでReadメソッドを起動中に、LONGまたはLONG RAW列データに対して指定された、InitialLONGFetchSizeの文字数またはバイト数がキャッシュに取り出されます。
デフォルトでは、InitialLONGFetchSizeは0に設定されています。この場合ODP.NETは、OracleDataReader オブジェクト上でのReadメソッドの起動中、LONGまたはLONG RAW列データのいずれもフェッチしません。データがキャッシュされないため、データベースのラウンド・トリップの原因となるLONGまたはLONG RAW列に対して型指定アクセッサ・メソッドが明示的に起動されると、LONGまたはLONG RAWデータがフェッチされます。
InitialLONGFetchSizeが0より大きな値に設定された場合、OracleDataReaderオブジェクトでReadメソッドを起動すると、ODP.NETにより、指定された量のデータがキャッシュされます。アプリケーションが型指定アクセッサ・メソッドによりInitialLONGFetchSize以下のデータ量を要求した場合、データベース・ラウンドトリップは発生しません。ただし、InitialLONGFetchSizeを超えるデータをフェッチするには、追加のデータベース・ラウンドトリップが必要です。
InitialLONGFetchSize文字数またはバイト数よりも多くのデータを取得するには、選択リストに次のいずれかが必要です。
-
主キー
-
ROWID -
一意の列 - (一意制約が定義されたか、または一意索引が作成された1セットの列として定義されたもの。セット内の少なくとも1列には、ここで定義された
NOTNULL制約があります)
選択リストに主キー列(ROWID)または一意の列がない状態で、LONGまたはLONG RAWデータ全体をフェッチするには、OracleCommandオブジェクトのInitialLONGFetchSizeプロパティのサイズを、検索に必要な文字数またはバイト数以上に設定します。
OracleDataReaderオブジェクトで適切な型指定アクセッサ・メソッド(LONGの場合GetChars、GetOracleStringまたはGetString、LONG RAWの場合GetOracleBinaryまたはGetBytes)がコールされたときに、LONGまたはLONG RAWデータが戻されます。
InitialLONGFetchSizeを-1に設定
InitialLONGFetchSizeを-1に設定すると、選択リストに主キー、ROWIDまたは一意の列を必要とせずに、SELECT問合せに対してデータベースからLONGまたはLONG RAWデータ全体をフェッチできます。
InitialLONGFetchSizeが-1に設定されると、OracleDataReaderオブジェクトでReadメソッドを起動中に、LONGまたはLONG RAWデータ全体が取り出され、キャッシュされます。OracleDataReaderオブジェクトでGetString、GetOracleString、GetChars、GetBytesまたはGetOracleBinaryをコールすると、列データ全体が戻されます。
LOBデータの取得
ODP.NETは、OracleDataReaderオブジェクトでReadメソッドを起動中に、データベースから行をフェッチおよびキャッシュします。この操作により取得されるLOB列データの量は、InitialLOBFetchSizeにより決定されます。
InitialLOBFetchSizeが0、0より大きな値または -1に設定されている場合に、アプリケーションがCLOB列およびBLOB列に対してコールできる型指定アクセッサ・メソッドの全リストを次に示します。
-
BLOB列に対してコールできるメソッド-
GetBytes -
GetValue -
GetValues -
GetOracleBinary -
GetOracleBlob -
GetOracleBlobForUpdate -
GetOracleValue -
GetOracleValues
-
-
CLOB列に対してコールできるメソッド-
GetChars -
GetString -
GetValue -
GetValues -
GetOracleString -
GetOracleClob -
GetOracleClobForUpdate -
GetOracleValue -
GetOracleValues
-
次の各項では、InitialLOBFetchSizeが、0、0より大きな値および-1に設定されている場合の動作の違いを説明します。
InitialLOBFetchSizeを0(ゼロ)に設定
デフォルトでは、InitialLOBFetchSizeプロパティは0です。この値では、LOBを選択した場合にそのクライアントLOBデータのフェッチをOracleDataReader Readの後まで(アクセッサを使用した場合など)遅延するようODP.NETに指定します。LOBの各値は、個々にアクセスされた時点にのみ取得されます。
このような取得方法を使用する利点は、クライアントのメモリーおよび帯域幅が節約されるということです。選択したLOBがきわめて大きい、またはエンド・ユーザーがすぐには使用する必要がない場合、あるいはその両方の場合、すべて同時ではなく必要に応じてLOBを取得する方がアプリケーションのパフォーマンスが向上します。
InitialLOBFetchSizeを0(ゼロ)より大きな値に設定
InitialLOBFetchSizeを0より大きな値に設定すると、OracleDataReaderオブジェクトに対するReadメソッドを起動中に、ODP.NETにより、選択された各LOBに対してInitialLOBFetchSizeの文字数またはバイト数までのLOBデータがキャッシュされます。最大値は2,147,483,647 (2GB)です。選択したLOBの合計サイズがこの数値より小さい場合は、LOBデータ全体が読み取られます。
1回または複数回のデータベース・ラウンドトリップですべてのLOBエントリをプリフェッチすると、ラウンドトリップが減るためアプリケーションのパフォーマンスが向上します。このアプローチは、大部分のLOBが小さい、またはエンド・ユーザーがほぼ即時に使用する場合、あるいはその両方の場合に最も利点を発揮します。フェッチ・サイズが大きくなるとメモリー消費量が増えるのが欠点です。
この項では、キャッシュされるInitialLOBFetchSize文字数またはバイト数よりも多くのデータをフェッチする方法について説明します。
InitialLOBFetchSizeプロパティに設定された値に関係なく、型指定アクセッサが起動されると残りのLOBデータが戻されます。指定されたInitialLOBFetchSizeよりも多くのデータを取得するために、主キー、ROWIDまたは一意の列を問合せ選択リストに含める必要はありません。
InitialLOBFetchSizeが0より大きな値であっても、GetOracleBlob、GetOracleClob、GetOracleBlobForUpdateおよびGetOracleClobForUpdateメソッドを起動できるようになりました。
InitialLOBFetchSizeを-1に設定
読取り操作中に選択し、設定したLOB当たり制限によって検出されていないすべてのLOBデータをフェッチするには、InitialLOBFetchSizeを-1に設定します。ODP.NETリリース12.1.0.2以上では、InitialLobFetchSizeを-1に設定したときの新しいデフォルト動作が導入されました。
LegacyEntireLOBFetch = 0のとき(デフォルト値)、LOB列で次の操作が呼び出されます。
-
OracleDataReader.GetOracleClob():OracleClobオブジェクトを返します。 -
OracleDataReader.GetOracleBlob(): returnsOracleBlobオブジェクトを返します。 -
OracleDataReader.GetOracleClobForUpdate():OracleClobオブジェクトを返します。 -
OracleDataReader.GetOracleBlobForUpdate():OracleBlobオブジェクトを返します。 -
OracleDataReader.GetOracleValue(): CLOB列に対してOracleClobオブジェクトを返します。 -
OracleDataReader.GetOracleValue(): BLOB列に対してOracleBlobオブジェクトを返します。 -
OracleDataAdapter.Fill()でProviderSpecificTypes=trueに設定:CLOB列をOracleClobにしてDataTableに移入します。 -
OracleDataAdapter.Fill()でProviderSpecificTypes=trueに設定:BLOB列をOracleBlobにしてDataTableに移入します。
以前の動作を使用する場合は、ODP.NET構成でLegacyEntireLobFetch = 1に設定します。
LegacyEntireLobFetch = 1でInitialLOBFetchSize = -1の場合、GetOracleClob、GetOracleClobForUpdate、GetOracleBlob、GetOracleBlobForUpdateの各メソッドはサポートされません。次の操作は、このシナリオでLOB列のために呼び出されます。
-
OracleDataReader.GetOracleClob():InvalidCastException()をスローします。 -
OracleDataReader.GetOracleBlob():InvalidCastException()をスローします。 -
OracleDataReader.GetOracleClobForUpdate():InvalidCastException()をスローします。 -
OracleDataReader.GetOracleBlobForUpdate():InvalidCastException()をスローします。 -
OracleDataReader.GetOracleValue():CLOB列に対してOracleStringオブジェクトを返します。 -
OracleDataReader.GetOracleValue():BLOB列に対してOracleBinaryオブジェクトを返します。 -
OracleDataAdapter.Fill()でProviderSpecificTypes=trueに設定:CLOB列をOracleStringにしてDataTableに移入します。 -
OracleDataAdapter.Fill()でProviderSpecificTypes=trueに設定:BLOB列をOracleBinaryにしてDataTableに移入します。
ODP.NET 12.1.0.2以前のリリースでは、InitialLOBFetchSizeを-1に設定することで、選択リストに主キー、ROWIDまたは一意の列がない場合も、SELECT問合せに対してデータベースからLOBデータ全体をフェッチできます。InitialLOBFetchSizeが-1に設定されると、OracleDataReaderオブジェクトでReadメソッドを起動中に、LOB列データ全体がフェッチおよびキャッシュされます。OracleDataReaderオブジェクトでGetString、GetOracleString、GetChars、GetBytesまたはGetOracleBinaryをコールすると、すべてのデータを取得できます。
InitialLOBFetchSizeが-1でLegacyEntireLobFetchが1のときにサポートされるメソッド
この項では、InitialLOBFetchSizeプロパティが-1に設定され、LegacyEntireLobFetchプロパティが1に設定されている場合に、CLOBおよびBLOBデータ型に対してサポートされているメソッドとサポートされていないメソッドをリストしています。
表3-17では、CLOBデータ型に対してサポートされているメソッドとサポートされていないメソッドをリストしています。
表3-17 InitialLOBFetchSizeが-1でLegacyEntireLobFetchが1のときにサポートされるOracleDataReader CLOBメソッド
| OracleDataReader CLOBメソッド | サポート対象 |
|---|---|
|
|
はい |
|
|
はい |
|
|
はい |
|
|
はい |
|
|
はい |
|
|
はい |
|
|
はい |
|
|
いいえ |
|
|
いいえ |
表3-18では、BLOBデータ型に対してサポートされているメソッドとサポートされていないメソッドをリストしています。
表3-18 InitialLOBFetchSizeが-1でLegacyEntireLobFetchが1のときにサポートされるOracleDataReader BLOBメソッド
| OracleDataReader BLOBメソッド | サポート対象 |
|---|---|
|
|
はい |
|
|
はい |
|
|
はい |
|
|
はい |
|
|
はい |
|
|
はい |
|
|
いいえ |
|
|
いいえ |
InitialLOBFetchSizeプロパティに関連したパフォーマンス上の考慮事項
この項では、異なる状況における、InitialLOBFetchSizeプロパティの様々な設定のメリットおよびデメリットについて説明します。
アプリケーションで、パフォーマンスとOracleBlobおよびOracleClob機能のどちらをとるかを選択する必要はありません。InitialLOBFetchSizeプロパティを設定すると、パフォーマンスは向上し、OracleBlobオブジェクトおよびOracleClobオブジェクトを使用する自由度はそのままです。
LOBデータのサイズが不明であったり、LOBデータのサイズが不規則に変化する場合は、InitialLOBFetchSizeプロパティをデフォルト値の0のままにしてください。これでも、ほとんどの場合でパフォーマンスが改善されます。
大部分の行についてInitialLOBFetchSizeプロパティのサイズをLOBデータ・サイズ以上に設定すると、パフォーマンスが劇的に改善されます。通常、InitialLOBFetchSizeプロパティは、問合せで戻される行の80%以上のLOBデータのサイズより大きい値に設定することをお薦めします。たとえば、LOBデータのサイズが行の80%で1KB未満で、行の20%で1MB以上である場合、InitialLOBFetchSizeプロパティを1KBに設定します。
1回のデータベース・ラウンドトリップでフェッチされる行数の制御
アプリケーションのパフォーマンスは、アプリケーションがフェッチする必要のある行数と、行の検索に必要なデータベース・ラウンドトリップの回数に依存します。
FetchSizeの使用
FetchSizeプロパティは、データベース・ラウンドトリップからフェッチされたデータをキャッシュするためにODP.NETが割り当てるメモリー・サイズの合計をバイトで表したものです。
FetchSizeプロパティは、状況に応じてOracleCommand、OracleDataReaderまたはOracleRefCursorオブジェクトで設定できます。これは、OracleDataAdapterを使用してDataSetまたはDataTableに移入を行う場合のフェッチ・サイズを制御します。
FetchSizeプロパティをOracleCommandオブジェクトで設定した場合、新しく作成されたOracleDataReaderは、OracleCommandオブジェクトのFetchSizeプロパティを継承します。この継承されたFetchSizeは、そのままにしておくか、継承された値を上書きするように変更できます。OracleDataReaderオブジェクトのFetchSizeプロパティは、最初のReadメソッドを起動する前に変更できます。このメソッドは、FetchSizeプロパティで指定されたメモリーを割り当てます。データベースからの後続のフェッチはすべて、そのOracleDataReaderに割り当てられた同じキャッシュを使用します。このため、最初のReadメソッドを起動した後にFetchSizeを変更しても影響はありません。
FetchSizeの微調整
FetchSizeプロパティを微調整することで、アプリケーションは、メモリー使用率、および1回のデータベース・ラウンドトリップでフェッチされる行数を制御して、パフォーマンスを向上させることができます。
たとえば、問合せが100行を戻し、各行が1024バイトある場合、FetchSizeプロパティを102400に設定すると、1回のデータベース・ラウンドトリップで100行をフェッチできます。同じ問合せで、FetchSizeプロパティを10240に設定すると、100行を検索するのに10回のデータベース・ラウンドトリップが必要になります。アプリケーションが結果セットからすべての行をフェッチする必要がある場合、最初の使用例の方が2番目の使用例より高速になります。ただし、アプリケーションが結果セットから最初の10行のみをフェッチする必要がある場合、100行ではなく10行のみをフェッチするため、2番目の使用例の方がパフォーマンスが向上します。次の10行をフェッチする場合、行1から10に割り当てられたメモリーが行11から20で再び使用されます。
FetchSizeが大きいほど、より多くのシステム・メモリーが使用されます。クライアント・システムのメモリー・リソースに制限がある場合、開発者は大きなフェッチ・サイズを設定できません。
RowSizeプロパティの使用
OracleCommandまたはOracleRefCursorオブジェクトのRowSizeプロパティには、SELECT文の実行後に行サイズ(バイト)が移入されます。FetchSizeプロパティは、RowSize値とデータベース・ラウンドトリップごとにフェッチされる行数の積に設定することで、RowSizeプロパティに応じた値に設定できます。
たとえば、FetchSizeをRowSize * 10に設定すると、OracleDataReaderオブジェクトでは、データベース・ラウンドトリップごとに10行のみが強制的にフェッチされます。各列のデータ長によってRowSizeが変わることはありません。RowSizeは、SELECT文が実行されるデータベース表のメタデータ情報から正確に決定されます。
RowSizeプロパティを使用すると、次の項で説明するように、設計時または実行時にFetchSizeプロパティを設定できます。
レジストリ内のFetchSize値の設定
HKLM\Software\Oracle\ODP.NET\ version\FetchSizeレジストリ・エントリは、特定のバージョンのODP.NETを使用するすべてのアプリケーションに対するデフォルトの結果セットのフェッチ・サイズをバイト単位で指定するように設定できます。または、アプリケーション構成ファイルまたはweb.configファイルのFetchSize属性で、特定のアプリケーションに対するデフォルト値を指定できます。デフォルトのフェッチ・サイズは131072バイトです。この値は、実行時にアプリケーションのFetchSizeプロパティをOracleCommandまたはOracleDataReaderに対してプログラムで設定することによって無視できます。
設計時のFetchSize値の設定
特定のSELECT文の行サイズが前の実行ですでにわかっている場合、OracleCommandオブジェクトのFetchSize値は、設計時に、その行サイズとアプリケーションがデータベース・ラウンドトリップごとにフェッチする必要がある行数の積に設定できます。OracleCommandオブジェクトのFetchSize値セットは、OracleCommandオブジェクトでExecuteReaderメソッドを起動したときに作成されたOracleDataReaderオブジェクトにより継承されます。OracleCommandオブジェクトでFetchSize値を設定するのではなく、OracleDataReaderオブジェクトで直接FetchSize値を設定することもできます。いずれの場合にも、実行時にRowSizeプロパティ値にアクセスしなくても、FetchSizeは設計時に設定されます。
実行時のFetchSize値の設定
設計時に行サイズがわからないアプリケーションでは、OracleCommandオブジェクトのRowSizeプロパティを使用して、OracleDataReaderオブジェクトのFetchSizeプロパティを設定できます。RowSizeプロパティは、行のサイズに基づいて、動的な方法でFetchSizeプロパティを設定します。
OracleCommandオブジェクトでExecuteReaderメソッドを起動してOracleDataReaderオブジェクトを取得した後に、RowSizeプロパティが行のサイズ(バイト)とともに移入されます。RowSizeプロパティを使用することで、アプリケーションは、OracleDataReaderオブジェクトのFetchSizeプロパティを、RowSizeプロパティ値とアプリケーションがデータベース・ラウンドトリップごとにフェッチする必要がある行数の積に動的に設定できます。この使用例では、実行時にRowSizeプロパティにアクセスすることでFetchSizeが設定されます。