5

私の状況でレコードセットオブジェクトを閉じるのに最適な例は次のうちどれですか?

1)

これはループ内のオブジェクトを閉じますが、次に移動するときに新しいオブジェクトを開きます。1000レコードがあった場合、これはオブジェクトを1000回開き、1000回閉じます。これは私が通常行うことです:

SQL = " ... "
Set rs1 = conn.Execute(SQL)
While NOT rs1.EOF

    SQL = " ... "
    Set rs2 = conn.Execute(SQL)
    If NOT rs2.EOF Then
        Response.Write ( ... )
    End If
    rs2.Close : set rs2 = Nothing

rs1.MoveNext
Wend
rs1.Close : Set rs1 = Nothing

2)

この例は私が知りたいことです。ループが終了するまでオブジェクトクロージャ(rs2.close)を保存すると、パフォーマンスが向上または低下しますか?1000のレコードがある場合、これは1000のオブジェクトを開きますが、一度だけ閉じます。

SQL = " ... "
Set rs1 = conn.Execute(SQL)
While NOT rs1.EOF

    SQL = " ... "
    Set rs2 = conn.Execute(SQL)
    If NOT rs2.EOF Then
        Response.Write ( ... )
    End If

rs1.MoveNext
Wend
rs1.Close : Set rs1 = Nothing
rs2.Close : set rs2 = Nothing

私は自分自身を十分に説明し、それがあまり愚かではないことを願っています。

アップデート

N + 1の問題(2番目のクエリ)を回避するために私のクエリを変更できると思う人には、次のようになります。

これはオンラインフォトライブラリ用です。2つのテーブルがあります。「photoSearch」と「photos」。最初の「photoSearch」には数列しかなく、「photoID」、「headline」、「caption」、「people」、「dateCaptured」、「keywords」など、写真の検索可能なすべてのデータが含まれています。(見出し、キャプション、人物、キーワード)に複数列の全文索引があります。2番目のテーブル「photos」には、すべての写真データが含まれています。高さ、幅、著作権、キャプション、ID、日付など。どちらも500K以上の行があり、見出しとキャプションのフィールドは2000文字以上を返すことがあります。

これは、クエリが現在どのように見えるかとほぼ同じです:(注意事項:全文検索では結合を使用できないため、キーワードは1つの列(「非正規化」テーブル)に格納されます。また、この種の擬似コードはアプリコードです。他の場所にあります-しかし、それは近いです)

SQL = "SELECT photoID FROM photoSearch
WHERE MATCH (headline, caption, people, keywords)
AGAINST ('"&booleanSearchStr&"' IN BOOLEAN MODE)
AND dateCaptured BETWEEN '"&fromDate&"' AND '"&toDate&"' LIMIT 0,50;"
Set rs1 = conn.Execute(SQL)
While NOT rs1.EOF

    SQL = "SELECT photoID, setID, eventID, locationID, headline, caption, instructions, dateCaptured, dateUploaded, status, uploaderID, thumbH, thumbW, previewH, previewW, + more FROM photos LEFT JOIN events AS e USING (eventID) LEFT JOIN location AS l USING (locationID) WHERE photoID = "&rs1.Fields("photoID")&";"
    Set rs2 = conn.Execute(SQL)
    If NOT rs2.EOF Then
        Response.Write ( .. photo data .. )
    End If
    rs2.Close

rs1.MoveNext
Wend
rs1.Close

テストしたところ、大きなテーブル「photos」の代わりに「photoSearch」という独自のテーブルにフルテキストインデックスを設定すると、速度がいくらか向上したように見えました。「photoSearch」テーブルは追加しませんでした。すでに存在していました。これは私のアプリではありません。2つのテーブルを結合して2番目のクエリを失おうとすると、インデックス作成がすべて失われ、非常に長い時間がかかるため、フルテキストで結合を使用できません。これが最も速い方法のようでした。フルテキストと結合の問題がなかったら、私はこれらのクエリの両方をすでに組み合わせていただろう。

4

3 に答える 3

4

これがそのことです。まず、写真IDを取得し、それが写真IDのみを保持する実際のテーブルであるとmysqlに認識させてから、実際のステートメントを作成します。追加のレコードセット接続は必要ありません...

そして、これを行うために最後から始めることを忘れないでください。説明付きのサンプルコードは次のとおりです。

ステップ1写真IDルックアップテーブルを作成して名前を付けます。これにより、PhotoIdルックアップテーブルになりますので、「PhotoIds」という名前を付けます。

SELECT photoID FROM photoSearch
WHERE MATCH (headline, caption, people, keywords)
AGAINST ('"&booleanSearchStr&"' IN BOOLEAN MODE)
AND dateCaptured BETWEEN '"&fromDate&"' AND '"&toDate&"' LIMIT 0,50) AS PhotoIds

ステップ2これで写真IDができたので、そこから情報を取得します。実際のテーブルの場合と同じように、WHERE句の直前に上記のステートメントを挿入します。私たちの「偽の」テーブルは、括弧の間になければならないことに注意してください。

SQL = "SELECT p.photoID, p.setID, p.eventID, p.locationID, p.headline, p.caption, + more FROM
    photos AS p,
    events AS e USING (p.eventID),
    location AS l USING (p.locationID),
    (SELECT photoID FROM photoSearch WHERE MATCH (headline, caption, people, keywords)
        AGAINST ('"&booleanSearchStr&"' IN BOOLEAN MODE) AND dateCaptured BETWEEN
        '"&fromDate&"' AND '"&toDate&"' LIMIT 0,50) AS PhotoIds
    WHERE p.photoID=PhotoIds.photoID;"

注:私はここにこれらのコードを書くだけで、テストはしていません。いくつかのスペルミスまたはsmtがあるかもしれません。ご不明な点がございましたらお知らせください。

今あなたの主な質問を取得します

特にexecuteメソッドを使用している場合は、実行されたクエリを閉じる必要はありません。Executeメソッドは、「INSERT」、「DELETE」、「UPDATE」などのレコードセットデータ(最初にコマンドを実行する目的)を返さない限り、実行後に閉じます。レコードセットオブジェクトを開かなかった場合、なぜ開かれたことがないものを閉じようとするのでしょうか。代わりに、Set Rs = Nothingを使用してオブジェクトの参照を解除し、ガベージコレクションに送信して、一部のシステムリソースを解放できます(これはmysql自体とは関係ありません)。「SELECT」クエリ(一部のデータを返すクエリ)を使用している場合は、レコードセットオブジェクト(ADODB.Recordset)を開く必要があります。開いた場合は、ジョブが終了したらすぐに閉じる必要があります。

最も重要なことは、各ページのロード後に「mysqlサーバーへのメイン接続」を閉じることです。したがって、接続を閉じるアルゴリズム(レコードセットを閉じるのではなく)をインクルードファイルに配置し、データベースに接続するすべてのページの最後に挿入することを検討してください。簡単に言うと、 Open()を使用した場合は、 Close()を使用する必要があります

于 2012-07-08T06:45:45.843 に答える
3

SQLステートメントを表示すると、それらを1つのSQLステートメントに結合する方法を示すことができるので、ループを1つだけ実行する必要があります。そうしないと、このような二重ループはサーバーのパフォーマンスに大きな打撃を与えます。しかし、ストアドプロシージャと結合を学ぶ前は、おそらく次のようにしていたでしょう。

 Set Conn = Server.CreateObject("Adodb.Connection")
 Conn.Open "ConnectionString"

 Set oRS = Server.CreateObject("Adodb.Recordset")
 oRS.Open "SQL STATEMENT", Conn

 Set oRS2 = Server.CreateObject("Adodb.Recordset")
 oRS2.ActiveConnection = Conn

 Do Until oRS.EOF

    oRS2.Open "SQL STATEMENT"
    If oRS2.EOF Then ...
    oRS2.Close

 oRS.Movenext
 Loop
 oRS.Close
 Set oRS = Nothing
 Set oRS2 = Nothing
 Set Conn = Nothing
于 2012-07-07T00:55:27.673 に答える
0

元の質問に直接答えていないのでコメントに入れてみましたが、長すぎました。

結合の代わりにサブクエリを使用して、2番目のクエリ内に外部クエリをネストしてみることができます。"... where photoID in(photoSearchからphotoIDを選択...)"。より良い結果が得られるかどうかはわかりませんが、試す価値があるかもしれません。そうは言っても、全文検索を使用すると、クエリの最適化方法が変わるため、適切なインデックスが何であるか(必要)を理解するのにさらに作業が必要になる場合があります。既存のパフォーマンスによっては、努力する価値がない場合があります。

この既存のコード/クエリが現在のボトルネックであることを確かに知っていますか?時々、そうでないかもしれないときにボトルネックであると私たちが考えるものを最適化することに時間を費やします... :)

ページレベルまたはこのメソッドのレベルのいずれかで、実行する可能性のある冗長なクエリの量を減らすために、いくつかのキャッシュロジックを検討することをお勧めします。検索パラメータを連結して、ある種のキャッシュにデータを格納するためのキーを形成することができます。もちろん、適切なキャッシュの無効化/有効期限ロジックを処理する必要があります。このようなボトルネックに非常に単純なキャッシュロジックが追加され、システムが100倍高速化するのを見てきました。

于 2012-07-07T05:29:50.377 に答える