[PRB] SQL からデータを取得するときに 80020009 エラーが発生する


現象


SQL テーブルから取得した "Text" 型または "BLOB" (Binary Large Object) 型のデータが含まれる Active Server Pages (ASP) ページ内のレコードセットにアクセスしたとき、次のエラーが発生します。
Microsoft OLE DB Provider for ODBC Drivers エラー '80020009'

原因


このエラーは、次の状況で発生することがあります。
Text フィールドまたは BLOB フィールドが、他の型のフィールドよりも前に選択されています。

解決方法


Microsoft SQL Server の BLOB フィールドを使用する場合は、BLOB フィールドを、結果セットの BLOB 以外の列の右側に配置する必要があります。確実に行うには、列の読み込みを左から右に行い、2 つの BLOB 列が結果セットの最後の 2 列にある場合に、最初の列を読み込んだ後 2 つ目の列を読み込むようにします。逆の順序で読み込まないようにしてください。


フィールド選択の正しい順序を実際に確認してみるために、Visual InterDev プロジェクトで新しい ASP ページを作成し、空白の ASP ページに次のコードを貼り付けます。接続する SQL Server に合わせて接続文字列を変更してください。


: このコードを実行する前に、Username=<username> および PWD=<strong password> を適切な値に変更する必要があります。ユーザー ID に、データベースでこの操作を実行するための適切な権限があることを確認してください。
   <%@ Language=VBScript %>
<HTML>
<BODY bgcolor=white>
<%
Set cn = Server.CreateObject("ADODB.Connection")
Set rs = Server.CreateObject("ADODB.Recordset")
'Open the connection.
cn.Open "dsn=yoursystemdsn;Username=<username>;PWD=<strong password>;database=pubs;"
'Open the recordset.
'Notice that the Blob field, pr_info, is last in the field order.
rs.Open "select pub_id, pr_info from pub_info", cn
While Not rs.EOF
Response.Write "<P>PR Info:<P>" & rs("pr_info")
Response.Write "<P>That was the PR Info for PubID " &
rs("pub_id")
rs.MoveNext
Wend
%>
</BODY>
</HTML>

状況


この動作は仕様です。ただし、SQL Server 用の 3.7 以降のドライバと Microsoft Data Access Components (MDAC) 2.1 SP2 以降を使用している場合には発生しません。


Microsoft Data Access Components の最新版は、次のマイクロソフト Web サイトからダウンロードできます。

詳細


SQL Server が回線にデータを送信すると、クライアントは基本的にネットワーク回線上でビット ストリームを順次受信します。バインドされた列の場合、値をローカル メモリのバッファにコピーしてキャッシュすることができるため、ドライバは、列のデータをメモリ バッファに転送します。データがローカル バッファに格納されると、任意の順序でデータを読み取ることができます。このため、すべての列が BLOB ではなく、バインドされている場合、結果の列を任意の順序で読み取ることができます。


BLOB 列を含めた場合、列の長さは約 2 GB になる可能性があり、BLOB の取得が完了するまではドライバが BLOB の大きさを正確に特定できないため、通常データ アクセス ライブラリはこれらの列をバインドしません。また、BLOB データをキャッシュすると大量のメモリが消費され、データ アクセス ライブラリとアプリケーションの両方でキャッシュするのは非効率的であるため、通常データ アクセス ライブラリは BLOB データをキャッシュしません。データ アクセス ドライバは、BLOB 列の内容を返すように要求されると、要求された列を読み込むために連続したデータ ストリームを取得する必要があるため、通常、要求された BLOB 列よりも前のバインドされてない列を廃棄します。このため、データが取得される順序に従って、結果セットを左から右に読み込む方がより効率的です。


これは SQL Server の動作です。Oracle などの他のクライアント/サーバー DBMS でも同じ動作になる場合がありますが、必ずしも同じではありません。


より適切な方法は、Text 列を使用しないことです。SQL Server は領域を 2K のチャンクに分けて割り当てるため、Text 列を使用すると、テキストの長さが非常に短い場合、保存領域の使用効率が低下します。また、トランザクション ログのダンプにも時間がかかるため、バックアップ時間にも影響を及ぼします。多くの場合、既存テーブルの主キー、チャンク番号列、および varchar (255) 列を含む別のテーブルを作成しておくのが良い方法です。テキストを必要な数だけ 255 文字のチャンクに分割し、新しいテーブルにチャンクの数だけ行を挿入します。多くの場合、このコードを作成するのに要する時間以上に、保存領域の使用効率の向上や、バックアップ時間の短縮に大きな効果を得ることができます。

関連情報


この資料は米国 Microsoft Corporation から提供されている Knowledge Base の Article ID 175239 (最終更新日 2005-02-22) を基に作成したものです。


この資料に含まれているサンプル コード/プログラムは英語版を前提に書かれたものをありのままに記述しており、日本語環境での動作は確認されておりません。