次の記事を読んだ後、著者のテストは ASP を使用する友人にとって非常に役立つことがわかりました。これは ASP だけでなく他の言語でも同様のはずです。サーバー上で動的コンテンツを生成することは、ASP を使用する主な理由の 1 つであるため、私たちが選択した最初のテスト プロジェクトは、動的コンテンツを応答ストリームに送信する最適な方法を決定することでした。基本的なオプション (およびそのいくつかのバリエーション) は 2 つあります。インライン ASP タグを使用する方法と、Response.Write ステートメントを使用する方法です。
これらのさまざまなアプローチをテストするために、いくつかの変数を定義してテーブルに挿入する単純な ASP ページを作成しました。このページは単純で実用的ではありませんが、個々の問題を切り分けてテストするには十分です。
2.1 ASP インライン タグの使用
最初のテストは、ASP のインライン タグ <%= x %> を使用することです (x は変数)。これは最も使いやすい方法であり、ページの HTML 部分が読みやすく、管理しやすくなります。
次のようにコードをコピーします。
<% オプションの明示的
ディム名
ディム姓
ディムミドルイニシャル
ディムアドレス
ディムシティ
薄暗い状態
DimPhoneNumber
薄暗い FAX番号
薄暗いメール
ディム誕生日
名 = ジョン
ミドルイニシャル = Q
姓 = 公開
住所 = 100 メインストリート
都市=ニューヨーク
州=ニューヨーク
電話番号 = 1-212-555-1234
ファックス番号 = 1-212-555-1234
電子メール = [email protected]
生年月日 = 1950/1/1
%>
<HTML>
<頭>
<TITLE>応答テスト</TITLE>
</HEAD>
<本体>
<H1>応答テスト</H1>
<表>
<tr><td><b>名:</b></td><td><%= 名 %></td></tr>
<tr><td><b>ミドルイニシャル:</b></td><td><%= MiddleInitial %></td></tr>
<tr><td><b>姓:</b></td><td><%= LastName %></td></tr>
<tr><td><b>アドレス:</b></td><td><%= アドレス %></td></tr>
<tr><td><b>都市:</b></td><td><%= 都市 %></td></tr>
<tr><td><b>状態:</b></td><td><%= 状態 %></td></tr>
<tr><td><b>電話番号:</b></td><td><%= PhoneNumber %></td></tr>
<tr><td><b>ファックス番号:</b></td><td><%= ファックス番号 %></td></tr>
<tr><td><b>電子メール:</b></td><td><%= 電子メール %></td></tr>
<tr><td><b>生年月日:</b></td><td><%= 生年月日 %></td></tr>
</テーブル>
</BODY>
</HTML>
/app1/response1.asp の完全なコード
最高記録 = 8.28 ミリ秒/ページ
2.2 Response.Write を使用して HTML コードの各行を出力する
前述のインライン マークアップ アプローチは、コンテキスト スイッチと呼ばれる操作が発生するため避けるべきであると述べている優れた文献が数多くあります。この操作は、Web サーバーによって処理されるコードのタイプが変更される (純粋な HTML の送信からスクリプト処理へ、またはその逆) ときに発生し、この切り替えには一定の時間がかかります。多くのプログラマーがこれを学んだ後、最初に反応するのは、Response.Write 関数を使用して HTML コードの各行を出力することです。
次のようにコードをコピーします。
...
Response.Write(<html>)
Response.Write(<head>)
Response.Write( <title>レスポンス テスト</title>)
Response.Write(</head>)
Response.Write(<本文>)
Response.Write(<h1>レスポンステスト</h1>)
Response.Write(<テーブル>)
Response.Write(<tr><td><b>名:</b></td><td> & 名 & </td></tr>)
Response.Write(<tr><td><b>ミドルイニシャル:</b></td><td> & MiddleInitial & </td></tr>)
...
/app1/response2.asp フラグメント
最高記録 = 8.28 ミリ秒/ページ
応答時間 = 8.08 ミリ秒/ページ
差 = -0.20 ms (2.4% 削減)
インライン マークアップ バージョンと比較して確認されたパフォーマンスの向上は非常に小さいため、単純に驚くべきことでした。これは、ページ内にさらに多くの関数呼び出しがあることが原因である可能性があります。ただし、この方法にはさらに大きな欠点があります。HTML コードが関数に埋め込まれているため、スクリプト コードが非常に長くなり、読み取りや保守が困難になります。
2.3 ラッパー関数の使用
Response.Write は、テキスト行の末尾に CRLF (復帰 - 改行、復帰 - 改行) を追加しません。これは、上記の方法を使用する際に最も残念な点です。 HTML コードはサーバー側で適切にフォーマットされていますが、ブラウザーに表示されるのはまだ 1 行の長いコードにすぎません。しかし、残念だったのはこの問題だけではありませんでした。CRLF を自動的に追加できる Response.WriteLn 関数が存在しないことがすぐにわかりました。自然な反応は、Response.Write のラッパー関数を作成し、各行の後に CRLF を追加することです。
...
writeCR(<tr><td><b>名:</b></td><td> & 名 & </td></tr>)
...
SUB writeCR(str)
Response.Write(str & vbCRLF)
エンドサブ
/app1/response4.asp フラグメント
最高記録 = 8.08 ミリ秒/ページ
応答時間 = 10.11 ミリ秒/ページ
差 = +2.03 ミリ秒 (25.1% 増加)
その結果、パフォーマンスが大幅に低下します。もちろん、これは主に、この方法では関数呼び出しの数が 2 倍になるためであり、パフォーマンスへの影響は非常に明白です。この使用法は絶対に避けるべきです。CRLF を使用すると各行の末尾に 2 バイトが追加され、これらの 2 バイトはブラウザがページを表示するのに役に立ちません。ほとんどの場合、ブラウザ側の HTML コードの美しい形式により、競合他社がページのデザインを読みやすく理解しやすくなります。
2.4 複数のResponse.Writeをマージする
関数のカプセル化に関する最後のテストを無視すると、次の論理的なステップは、別々の Response.Write ステートメントのすべての文字列を 1 つのステートメントにマージすることです。これにより、関数呼び出しの数が減り、コードの効率が向上します。
次のようにコードをコピーします。
Response.Write(<html> & _
<頭> & _
<title>応答テスト</title> & _
</head> & _
<本文> & _
<h1>応答テスト</h1> & _
<テーブル> & _
<tr><td><b>名:</b></td><td> & 名 & </td></tr> & _
...
<tr><td><b>生年月日:</b></td><td> & 生年月日 & </td></tr> & _
</テーブル> & _
</body> & _
</html>)
/app1/response3.asp フラグメント
最高記録 = 8.08 ミリ秒/ページ
応答時間 = 7.05 ミリ秒/ページ
差 = -1.03 ms (12.7% 削減)
これは断然最良の方法です。
2.5 複数のResponse.Writeを結合し、各行の末尾にCRLFを追加します。
HTML コードがブラウザ側で美しく見えるかどうかを非常に気にする人もいます。そのため、vbCRLF 定数を使用して HTML コードの各行の末尾にキャリッジ リターンを追加します。他のテスト コードは上記の例と同じです。 。
...
Response.Write(<html> & vbCRLF & _
<頭> & vbCRLF & _
<title>応答テスト</title> & vbCRLF & _
</head> & vbCRLF & _
...
/app1/response5.asp フラグメント
最高記録 = 7.05 ミリ秒/ページ
応答時間 = 7.63 ミリ秒/ページ
差 = +0.58 ミリ秒 (8.5% 増加)
その結果、パフォーマンスがわずかに低下します。これは、おそらく文字列連結操作の追加と出力テキストの増加が原因と考えられます。
2.6 コメント
上記の ASP 出力テストの結果に基づいて、次のエンコード ルールが得られます。
埋め込み ASP を過度に使用しないようにします。
できるだけ多くの Response.Write ステートメントを 1 つのステートメントに結合します。
CRLF を追加するためだけに Response.Write をカプセル化しないでください。
HTML 出力をフォーマットする場合は、Response.Write ステートメントの直後に CRLF を追加します。
概要: ASP によって動的に生成されたコンテンツを出力する最も効率的な方法は何ですか?データベースのレコードセットを抽出する最良の方法は何ですか?この記事では、このような ASP 開発における 20 近くの一般的な問題をテストします。テスト ツールによって表示される時間は、通常は当然と思われている問題が注目に値するだけでなく、中には予期せぬ秘密が隠されているということを示しています。
1. テストの目的
この記事の最初の部分では、ASP 開発におけるいくつかの基本的な問題を検討し、ページに配置されたコードがパフォーマンスにどのような影響を与えるかを読者が理解できるように、いくつかのパフォーマンス テストの結果を示します。 ADO は、Microsoft によって開発された汎用の使いやすいデータベース インターフェイスです。ADO を介したデータベースとの対話は、ASP の最も重要なアプリケーションの 1 つであることがわかります。第 2 部では、この問題について説明します。
ADO が提供する機能は非常に広範であるため、この記事を準備する際の最大の困難は、問題の範囲をどのように定義するかということです。大量のデータを抽出すると Web サーバーの負荷が大幅に増加する可能性があることを考慮して、このセクションの主な目的は、ADO レコードセットを操作するための最適な構成を見つけることであると判断しました。ただし、問題の範囲を狭めた後でも、ADO は同じタスクを完了するためにさまざまな方法を使用できるため、依然として大きな困難に直面しています。たとえば、レコードセットは Recordset クラスだけでなく、Connection クラスや Command クラスからも抽出できます。レコードセット オブジェクトを取得した後でも、パフォーマンスに大きく影響する可能性のある操作メソッドが多数あります。ただし、パート 1 と同様に、可能な限り幅広い問題をカバーするように努めます。
具体的には、このセクションの目的は、次の質問に答えるために十分な情報を収集することです。
ADOVBS.inc は include を通じて参照する必要がありますか?
lレコードセットを使用する場合、別の接続オブジェクトを作成する必要がありますか?
lレコードセットを抽出する最良の方法は何ですか?
lどのカーソルタイプとレコードロック方法が最も効率的ですか?
lローカルレコードセットを使用する必要がありますか?
lレコードセットのプロパティを設定する最良の方法は何ですか?
lレコードセット内のフィールド値を参照するにはどの方法が最も効率的ですか?
l一時的な文字列を使用して出力を収集するのは良い方法ですか?
2. テスト環境
このテストでは合計 21 個の ASP ファイルが使用されました。これらの ASP ファイルはこの記事の最後からダウンロードできます。各ページは 3 つの異なるクエリを実行し、それぞれ 0、25、250 レコードを返すように設定されています。これは、ページ自体の初期化と実行のオーバーヘッドを、レコードセットのループのオーバーヘッドから分離するのに役立ちます。
テストを容易にするために、データベース接続文字列と SQL コマンド文字列は、アプリケーション変数として Global.asa に保存されます。テスト データベースは SQL Server 7.0 であるため、接続文字列では接続プロバイダーとして OLEDB を指定し、テスト データは SQL Server の Northwind データベースから取得されます。 SQL SELECT コマンドは、NorthWind Orders テーブルから 7 つの指定されたフィールドを抽出します。
次のようにコードをコピーします。
<SCRIPT LANGUAGE=VBScript RUNAT=サーバー>
サブアプリケーション_OnStart
アプリケーション(接続) = プロバイダ=SQLOLEDB & _
サーバー=私のサーバー & _
uid=sa;
pwd=;
DATABASE=北風
アプリケーション(SQL) = SELECTTOP 0OrderID, & _
顧客ID、& _
従業員ID、& _
注文日、& _
必須日付、& _
発送日、& _
貨物と_
FROM[注文]
エンドサブ
</スクリプト>
'代替 SQL - 25 レコード
アプリケーション(SQL) = SELECTTOP 25OrderID, & _
顧客ID、& _
従業員ID、& _
注文日、& _
必須日付、& _
発送日、& _
貨物と_
FROM[注文]
'代替 SQL-250 レコード
アプリケーション(SQL) = SELECTTOP 250 OrderID, & _
顧客ID、& _
従業員ID、& _
注文日、& _
必須日付、& _
発送日、& _
貨物と_
FROM[注文]
テスト サーバーの構成は次のとおりです: 450 Mhz Pentium、512 MB RAM、NT Server 4.0 SP5、MDAC 2.1 (データ アクセス コンポーネント)、および Microsoft Scripting Engine バージョン 5.0。 SQL Server は同様の構成の別のマシンで実行されています。最初のパートと同様に、引き続き Microsoft Web Application Stress Tool を使用して、最初のページ要求からサーバーから受信した最後のバイトまでの時間 (TTLB、最後のバイトまでの時間) を記録します。時間はミリ秒単位です。テスト スクリプトは各ページを 1300 回以上呼び出し、実行に約 20 時間かかりました。以下に示す時間は、セッションの平均 TTLB です。最初の部分と同様に、コードの効率性のみに関心があり、コードのスケーラビリティやサーバーのパフォーマンスには関心がないことに注意してください。
また、サーバーバッファリングが有効になっていることにも注意してください。さらに、すべてのファイル名を同じ長さにするために、一部のファイル名には 1 つ以上のアンダースコアが埋め込まれています。
3. 最初のテスト
最初のテストでは、Microsoft ASP ADO サンプルにある典型的なシナリオをシミュレートするレコードセットを抽出しました。この例 (ADO__01.asp) では、まず接続を開いてから、レコードセット オブジェクトを作成します。もちろん、ここでのスクリプトは、この記事の最初の部分でまとめたコーディング ルールに従って最適化されています。
次のようにコードをコピーします。
<% 明示的なオプション %>
<!-- #Include file=ADOVBS.INC -->
<%
ディムオブジェクトコン
薄暗いobjRS
応答.書き込み(_
<HTML><HEAD> & _
<TITLE>ADO テスト</TITLE> & _
</HEAD><BODY> _
)
objConn = Server.CreateObject(ADODB.Connection) を設定します。
objConn.Open Application(Conn)
objRS = Server.CreateObject(ADODB.Recordset) を設定します。
objRS.ActiveConnection = objConn
objRS.CursorType = adOpenForwardOnly
objRS.LockType = adLockReadOnly
objRS.Open Application(SQL)
objRS.EOF の場合
Response.Write(レコードが見つかりません)
それ以外
'見出しを書く
応答.書き込み(_
<TABLE BORDER=1> & _
<TR> & _
<TH>注文ID</TH> & _
<TH>顧客ID</TH> & _
<TH>従業員ID</TH> & _
<TH>注文日</TH> & _
<TH>必須日付</TH> & _
<TH>発送日</TH> & _
<TH>運賃</TH> & _
</TR> _
)
'データを書き込む
objRS.EOF ではないときに実行します
応答.書き込み(_
<TR> & _
<TD> & objRS(OrderID) & </TD> & _
<TD> & objRS(顧客ID) & </TD> & _
<TD> & objRS(従業員ID) & </TD> & _
<TD> & objRS(OrderDate) & </TD> & _
<TD> & objRS(RequiredDate) & </TD> & _
<TD> & objRS(発送日) & </TD> & _
<TD> & objRS(貨物) & </TD> & _
</TR> _
)
objRS.MoveNext
ループ
Response.Write(</TABLE>)
終了の場合
objRS.Close
objConn.Close
objRS = なしを設定します
objConn = なしを設定します
Response.Write(</BODY></HTML>)
%>
テスト結果は次のとおりです。
各列の数字の意味を見てみましょう。
0 は、0 レコードのページに必要な TTLB (ミリ秒単位) を返します。すべてのテストにおいて、この値は、レコードセット データの反復処理の時間を除いた、ページ自体の生成 (オブジェクトの作成を含む) にかかる時間のオーバーヘッドとみなされます。
25 レコードをフェッチして表示するには 25 TTLB (ミリ秒)
合計時間/2525 列の TTLB を 25 で割った値が、レコードごとの平均時間コストの合計です。
disp time/2525 列 TTLB から 0 列 TTLB を引いて、25 で割ります。この値は、レコードセットをループしながら 1 つのレコードを表示するのに必要な時間を反映しています。
250 250 レコードの TTLB を抽出して表示します。
tot time/250250 列の TTLB を 25 で割ります。この値は、1 つのレコードの平均時間コストの合計を表します。
disp time/250 列 250 の TTLB が列 0 の TTLB から減算され、250 で除算されます。この値は、レコードセットをループしながら 1 つのレコードを表示するのに必要な時間を反映しています。
上記のテスト結果は、次のテスト結果と比較するために使用されます。
4. ADOVBS.inc はインクルードを通じて参照する必要がありますか?
Microsoft が提供する ADOVBS.inc には、ADO プロパティ定数のほとんどを定義する 270 行のコードが含まれています。この例では、ADOVBS.inc から 2 つの定数のみを参照しています。したがって、このテスト (ADO__02.asp) では、含まれているファイル参照を削除し、プロパティを設定するときに対応する値を直接使用しました。
objRS.CursorType = 0?'
objRS.LockType = 1' adLockReadOnly
ページのオーバーヘッドが 23% 減少していることがわかります。ここでの変更はループ内のレコードセット操作に影響を与えないため、この値は個々のレコードのフェッチおよび表示時間には影響しません。 ADOVBS.inc 参照の問題を解決するには、いくつかの方法があります。 ADOVBS.inc ファイルを参照として使用し、コメントで設定を説明することをお勧めします。パート 1 で述べたように、コメントを適度に使用しても、コードの効率への影響は最小限であることに注意してください。もう 1 つの方法は、必要な定数を ADOVBS.inc ファイルからページにコピーすることです。
この問題を解決する良い方法もあります。それは、ADO タイプ ライブラリにリンクして、すべての ADO 定数を直接利用できるようにすることです。すべての ADO 定数に直接アクセスするには、次のコードを Global.asa ファイルに追加します。
<!--METADATA TYPE=typelib
FILE=C:プログラム ファイル共通ファイルSYSTEMADOmsado15.dll
NAME=ADODB タイプ ライブラリ -->
または:
<!--METADATA TYPE=typelib
UUID=00000205-0000-0010-8000-00AA006D2EA4
NAME=ADODB タイプ ライブラリ -->
したがって、最初のルールは次のとおりです。
lADOVBS.inc ファイルを含めることは避け、他の方法で ADO 定数にアクセスして使用してください。
5. レコードセットを使用する場合、別の接続オブジェクトを作成する必要がありますか?
この質問に正しく答えるには、2 つの異なる条件下でテストを分析する必要があります。1 つ目は、ページにデータベース トランザクションが 1 つだけあること、2 つ目は、ページに複数のデータベース トランザクションがあることです。
前の例では、別の Connection オブジェクトを作成し、それを Recordset の ActiveConnection プロパティに割り当てました。ただし、ADO__03.asp に示すように、接続文字列を ActiveConnection プロパティに直接割り当てることもでき、スクリプト内で Connection オブジェクトを初期化および構成する追加の手順を省略できます。
objRS.ActiveConnection = アプリケーション(接続)
Recordset オブジェクトは接続を作成する必要がありますが、この時点での作成は高度に最適化された条件で実行されます。その結果、ページのオーバーヘッドは前回のテストと比較してさらに 23% 減少し、予想通り、1 つのレコードの表示時間は大幅に変化しませんでした。
したがって、2 番目のルールは次のとおりです。
lレコードセットを 1 つだけ使用する場合は、接続文字列を ActiveConnection プロパティに直接割り当てます。
次に、ページで複数のレコード セットが使用されている場合でも、上記のルールが有効であるかどうかを確認します。この状況をテストするために、前の例を 10 回繰り返す FOR ループを導入します。このテストでは、次の 3 つのバリエーションを見ていきます。
まず、ADO__04.asp に示すように、各ループで Connection オブジェクトが確立および破棄されます。
次のようにコードをコピーします。
薄暗い私
i = 1 ~ 10 の場合
objConn = Server.CreateObject(ADODB.Connection) を設定します。
objConn.Open Application(Conn)
objRS = Server.CreateObject(ADODB.Recordset) を設定します。
objRS.ActiveConnection = objConn
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application(SQL)
objRS.EOF の場合
Response.Write(レコードが見つかりません)
それ以外
'見出しを書く
...
'データを書き込む
...
終了の場合
objRS.Close
objRS = なしを設定します
objConn.Close
objConn = なしを設定します
次
次に、ADO__05.asp に示すように、ループの外側で Connection オブジェクトを作成し、このオブジェクトをすべてのレコードセットと共有します。
次のようにコードをコピーします。
objConn = Server.CreateObject(ADODB.Connection) を設定します。
objConn.Open Application(Conn)
薄暗い私
i = 1 ~ 10 の場合
objRS = Server.CreateObject(ADODB.Recordset) を設定します。
objRS.ActiveConnection = objConn
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application(SQL)
objRS.EOF の場合
Response.Write(レコードが見つかりません)
それ以外
'見出しを書く
...
'データを書き込む
...
終了の場合
objRS.Close
objRS = なしを設定します
次
objConn.Close
objConn = なしを設定します
3 番目に、ADO__06.asp に示すように、各ループの ActiveConnection プロパティに接続文字列を割り当てます。
次のようにコードをコピーします。
薄暗い私
i = 1 ~ 10 の場合
objRS = Server.CreateObject(ADODB.Recordset) を設定します。
objRS.ActiveConnection = アプリケーション(接続)
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application(SQL)
objRS.EOF の場合
Response.Write(レコードが見つかりません)
それ以外
'見出しを書く
...
'データを書き込む
...
終了の場合
objRS.Close
objRS = なしを設定します
次
ご想像のとおり、ループ内で接続オブジェクトを作成および破棄するのは、最も効率の悪い方法です。ただし、驚くべきことに、ループ内で接続文字列を ActiveConnection プロパティに直接割り当てると、単一の Connection オブジェクトを共有するよりもわずかに遅くなるだけです。
それにもかかわらず、3 番目のルールは次のようにする必要があります。
l同じページで複数のレコード セットが使用されている場合は、単一の接続オブジェクトを作成し、ActiveConnection プロパティを通じて共有します。
6. どのカーソル タイプとレコード ロック方法が最も効率的ですか?
これまでのすべてのテストでは、レコードセットへのアクセスに前方専用カーソルのみを使用してきました。 ADO がレコード セット用に提供するカーソルには、静的スクロール可能カーソル、動的スクロール可能カーソル、キー セット カーソルの 3 種類があります。各カーソルは、前のレコードと次のレコードへのアクセス、他のプログラムによるデータの変更を表示できるかどうかなど、さまざまな機能を提供します。ただし、各カーソル タイプの機能の詳細については、この記事の範囲を超えています。次の表は、さまざまなカーソル タイプの比較分析です。
他のすべてのカーソル タイプでは、前方専用カーソルと比較して追加のオーバーヘッドが必要であり、これらのカーソルは一般にループ内での速度が遅くなります。したがって、次の注意事項を共有したいと思います。決してこのように考えないでください。まあ、私は動的カーソルを使用することがあるので、常にこのカーソルを使用します。
同じ意見がレコード ロック方法の選択にも当てはまります。前回のテストでは読み取り専用ロック方式のみを使用しましたが、他にも保守的、オープン、オープン バッチ処理という 3 つの方式があります。カーソルの種類と同様、これらのロック メソッドはさまざまな機能を提供し、レコードセット データの操作を制御します。
次のルールに到達します。
lタスクに適した最も単純なカーソルの種類とレコードのロック方法を使用します。
7. レコード セットを抽出するにはどの方法を使用するのが最適ですか?
これまで、Recordset オブジェクトを作成してレコードセットを抽出してきましたが、ADO には間接的なレコードセット抽出メソッドも用意されています。次のテストでは、ADO__03.asp と Connection オブジェクト (CONN_01.asp) から直接レコードセットを作成することを比較します。
次のようにコードをコピーします。
objConn = Server.CreateObject(ADODB.Connection) を設定します。
objConn.Open Application(Conn)
Set objRS = objConn.Execute(アプリケーション(SQL))
ページのオーバーヘッドがわずかに増加していますが、1 つのレコードの表示時間は変わっていないことがわかります。
Command オブジェクトから直接レコードセット オブジェクト (CMD__02.asp) を作成する方法を見てみましょう。
次のようにコードをコピーします。
objCmd = Server.CreateObject(ADODB.Command) を設定します。
objCmd.ActiveConnection = アプリケーション(接続)
objCmd.CommandText = アプリケーション(SQL)
objRS = objCmd.Execute を設定します
同様に、ページのオーバーヘッドはわずかに増加しますが、単一レコードの表示時間は大幅に変わりません。後者の 2 つの方法のパフォーマンスの差はわずかですが、考慮すべき重要な問題があります。
Recordset クラスを通じてレコードセットを作成すると、レコードセットの処理を最も柔軟に制御できます。後者の 2 つの方法では圧倒的なパフォーマンスが得られないため、デフォルトで返されるカーソル タイプとレコード ロック方法を主に考慮します。場合によっては、デフォルト値が必ずしも最適であるとは限りません。
したがって、後者の 2 つの方法のどちらかを選択する特別な理由がない限り、次のルールを考慮することをお勧めします。
l 最高のパフォーマンスと柔軟性を得るには、ADODB.Recordset クラスを通じてレコードセットをインスタンス化します。
8. ローカル レコードセットを使用する必要がありますか?
ADO では、ローカル (クライアント) レコード セットの使用が許可されており、クエリが完了すると、レコード セット内のすべてのデータが抽出され、ローカル カーソルを使用してレコード セット内のデータにアクセスできます。将来的には、接続の解放が便利になります。ローカル レコードセットの使用は、データをオフラインで使用する必要があるリモート データ サービスにアクセスする場合に重要ですが、通常のアプリケーションにも役立ちますか?
次に、CursorLocation 属性を追加し、レコードセットを開いた後に接続 (CLIENT1.asp) を閉じます。
次のようにコードをコピーします。
objRS = Server.CreateObject(ADODB.Recordset) を設定します。
objRS.CursorLocation = 2' adUseClient
objRS.ActiveConnection = アプリケーション(接続)
objRS.LockType = 1?'
objRS.Open Application(SQL)
objRS.ActiveConnection = なし
理論的には、このアプローチは 2 つの理由で効率性が向上します。1 つ目は、レコード間を移動するときに接続を介してデータを繰り返し要求することが回避されることです。2 つ目は、リソース要件が緩和されることです。ただし、上の表から、ローカル レコードセットの使用は明らかに効率の向上に役立たないことがわかります。これは、ローカル レコードセットを使用する場合、プログラムの設定に関係なく、カーソルが常に静的タイプになることが原因である可能性があります。
ルール 6 は次のとおりです。
lレコードセットのローカライズが本当に必要でない限り、これは避けるべきです。
10. レコードセット内のフィールド値を参照するために使用する最も効率的な方法はどれですか?
10.1 テスト
これまで、レコードセット内のフィールド値を名前で参照してきました。この方法は、毎回対応するフィールドを見つける必要があるため、あまり効率的ではありません。これを実証するために、次のテストでは、コレクション (ADO__08.asp) 内のインデックスによってフィールドの値を参照します。
次のようにコードをコピーします。
'データを書き込む
objRS.EOF ではないときに実行します
応答.書き込み(_
<TR> & _
<TD> & objRS(0) & </TD> & _
<TD> & objRS(1) & </TD> & _
<TD> & objRS(2) & </TD> & _
<TD> & objRS(3) & </TD> & _
<TD> & objRS(4) & </TD> & _
<TD> & objRS(5) & </TD> & _
<TD> & objRS(6) & </TD> & _
</TR> _
)
objRS.MoveNext
ループ
予想どおり、ページ オーバーヘッドにもわずかな変化があります (おそらくコードがわずかに削減されたため)。ただし、このアプローチによる表示時間の改善は非常に顕著です。
次のテストでは、すべてのフィールドを変数 (ADO__09.asp) に個別にバインドします。
次のようにコードをコピーします。
objRS.EOF の場合
Response.Write(レコードが見つかりません)
それ以外
'見出しを書く
...
ディム fld0
ディム fld1
ディム fld2
ディム fld3
ディム fld4
ディム fld5
ディム fld6
fld0 = objRS(0) を設定します。
fld1 = objRS(1) を設定します。
fld2 = objRS(2) を設定します。
fld3 = objRS(3) を設定します。
fld4 = objRS(4) を設定します。
fld5 = objRS(5) を設定します。
fld6 = objRS(6) を設定します。
'データを書き込む
objRS.EOF ではないときに実行します
応答.書き込み(_
<TR> & _
<TD> & fld0 & </TD> & _
<TD> & fld1 & </TD> & _
<TD> & fld2 & </TD> & _
<TD> & fld3 & </TD> & _
<TD> & fld4 & </TD> & _
<TD> & fld5 & </TD> & _
<TD> & fld6 & </TD> & _
</TR> _
)
objRS.MoveNext
ループ
fld0 = 何も設定しない
fld1 = 何も設定しない
fld2 = なしを設定します
fld3 = 何も設定しない
fld4 = なしを設定します
fld5 = なしを設定します
fld6 = 何も設定しない
Response.Write(</TABLE>)
終了の場合
これはこれまでの最高記録です。 1 つのレコードの表示時間が 0.45 ミリ秒未満に短縮されたことに注意してください。
上記のスクリプトはすべて、結果レコード セットの構造をある程度理解する必要があります。たとえば、列ヘッダーでフィールド名を直接使用して、各フィールド値を個別に参照します。次のテストでは、フィールド コレクションを走査することによってフィールド データが取得されるだけでなく、フィールド タイトルも同じ方法で取得されます。これは、より動的なソリューション (ADO__10.asp) です。
次のようにコードをコピーします。
objRS.EOF の場合
Response.Write(レコードが見つかりません)
それ以外
' 見出しを書き込みます Response.Write(<TABLE BORDER=1><TR>)
objRS.Fields の各 objFld について
Response.Write(<TH> & objFld.name & </TH>)
次
Response.Write(</TR>)
'データを書き込む
objRS.EOF ではないときに実行します
応答.書き込み(<TR>)
objRS.Fields の各 objFld について
? Response.Write(<TD> & objFld.value & </TD>)
次
Response.Write(</TR>)
objRS.MoveNext
ループ
Response.Write(</TABLE>)
終了の場合
ご覧のとおり、コードのパフォーマンスは低下していますが、それでも ADO__07.asp よりも高速です。
次のテスト例は、前の 2 つの方法を折衷したものです。動的に割り当てられた配列にフィールド参照を保存することでパフォーマンスを向上させながら、動的機能を維持し続けます。
次のようにコードをコピーします。
objRS.EOF の場合
Response.Write(レコードが見つかりません)
それ以外
ディム fldCount
fldCount = objRS.Fields.Count
ディム fld()
ReDim fld(fldCount)
薄暗い私
i = 0 ~ fldCount-1 の場合
fld(i) = objRS(i) を設定します。
次
'見出しを書く
Response.Write(<TABLE BORDER=1><TR>) i = 0 ~ fldCount-1 の場合
Response.Write(<TH> & fld(i).name & </TH>)
次
Response.Write(</TR>)
'データを書き込む
objRS.EOF ではないときに実行します
応答.書き込み(<TR>)
i = 0 ~ fldCount-1 の場合
Response.Write(<TD> & fld(i) & </TD>)
次
Response.Write(</TR>)
objRS.MoveNext
ループ
i = 0 ~ fldCount-1 の場合
fld(i) = なしを設定します
次
Response.Write(</TABLE>)
終了の場合
これまでの最高のものには及ばないものの、最初のいくつかの例よりも高速であり、あらゆるレコードのセットを動的に処理できるという利点があります。
以前のテスト コードと比較して、次のテスト コードは根本的に変更されています。 Recordset 自体に直接アクセスするのではなく、Recordset オブジェクトの GetRows メソッドを使用して、データの反復のために配列にデータを設定します。 GetRows を呼び出した直後に Recordset が Nothing に設定されることに注意してください。これは、システム リソースができるだけ早く解放されることを意味します。また、配列の最初の次元がフィールドを表し、2 番目の次元が行 (ADO__12.asp) を表すことに注意してください。
次のようにコードをコピーします。
objRS.EOF の場合
Response.Write(レコードが見つかりません)
objRS.Close
objRS = なしを設定します
それ以外
'見出しを書く
...
'配列を設定
薄暗いarrRS
arrRS = objRS.GetRows
'レコードセットを早めに閉じる
objRS.Close
objRS = なしを設定します
'データを書き込む
ディムナム行
ディムナムフィールド
薄暗い列
薄暗いフォルダ
numFlds = Ubound(arrRS, 1)
numRows = Ubound(arrRS, 2)
row= 0 ~ numRows の場合
応答.書き込み(<TR>)
fld = 0 ~ numFlds の場合
Response.Write(<TD> & arrRS(fld, row) & </TD>)
次
Response.Write(</TR>)
次
Response.Write(</TABLE>)
終了の場合
GetRows メソッドを使用すると、レコードセット全体が配列に抽出されます。レコード セットが非常に大きい場合にはリソースの問題が発生する可能性がありますが、MoveNext や EOF のチェックなどの関数呼び出しがキャンセルされるため、ループ内のデータへのアクセスは実際に高速になります。
速度には代償が伴いますが、レコードセットのメタデータは失われます。この問題を解決するには、GetRows を呼び出す前にレコードセット オブジェクトからヘッダー情報を抽出します。また、データ型やその他の情報も事前に抽出できます。また、テストにおけるパフォーマンス上の利点は、レコード セットが大きい場合にのみ発生することに注意してください。
このセットの最後のテストでは、レコードセットの GetString メソッドを使用します。 GetString メソッドは、レコードセット全体を大きな文字列に抽出し、区切り文字 (ADO__13.asp) を指定できるようにします。
次のようにコードをコピーします。
objRS.EOF の場合
Response.Write(レコードが見つかりません)
objRS.Close
objRS = なしを設定します
それ以外
'見出しを書く
...
'配列を設定
ディム strTable
strTable = objRS.GetString (2, , </TD><TD>, </TD></TR><TR><TD>)
'レコードセットを早めに閉じる
objRS.Close
objRS = なしを設定します
Response.Write(strTable & </TD></TR></TABLE>)
終了の場合