2017-12-20 16 views
1

毎月問題なく動作している毎晩実行されるファイルがあります。突然、クエリタイムアウトエラーが発生します。クイックトレースを見ると、毎回何らかの二次照会(更新)に失敗していることがわかります。Do While Not.EOFのタイムアウト内でクエリを更新する

コード実行の非常に一般的な概要に:

strSQL = "EXEC usp_GET_listofRecords" 
rsRun(recSet, strSQL) 
Do While Not recSet.EOF 

    If recSet("condition") = 0 Then 
     strSQL2 = "UPDATE t_table SET status=0 WHERE id=" & recSet("id") 
     rsRun2(recSet2, strSQL2) 
     rsClose(recSet2) 

    ElseIf recSet("condition") = 1 Then 
     strSQL2 = "UPDATE t_table SET status=1 WHERE id=" & recSet("id") 
     rsRun2(recSet2, strSQL2) 
     rsClose(recSet2) 

    ElseIf recSet("condition") = 3 Then 
     strSQL2 = "UPDATE t_table SET status=3 WHERE id=" & recSet("id") 
     rsRun2(recSet2, strSQL2) 
     rsClose(recSet2) 

    End if 
    recSet.MoveNext 
Loop 
rsClose(recSet) 

これが最後に何ヶ月のために正常に動作しており、今では、更新のいずれかをヒットするたびに失敗しました。

編集:

strSQL = "EXEC usp_GET_listofRecords" 
rsRun(recSet, strSQL) 
Do While Not recSet.EOF 

    If recSet("condition") = 0 Then 
     strSQL2 = strSQL2 & "UPDATE t_table SET status=0 WHERE id=" & recSet("id") & "; " 

    ElseIf recSet("condition") = 1 Then 
     strSQL2 = strSQL2 & = "UPDATE t_table SET status=1 WHERE id=" & recSet("id") & "; " 

    ElseIf recSet("condition") = 3 Then 
     strSQL2 = strSQL2 & = "UPDATE t_table SET status=3 WHERE id=" & recSet("id") & "; " 

    End if 

    recSet.MoveNext 
Loop 
rsClose(recSet) 

rsRun recSet, strSQL2 
rsClose(recSet) 

編集2:と呼ばれる機能を含む:

Function rsRun(recSet, strSQL) 
    Call OpenDB() 
    Set recSet = Server.CreateObject("ADODB.Recordset") 
    recSet.Open strSQL, dbConn 
End Function 

Function rsRun2(recSet2, strSQL2) 
    Call OpenDB() 
    Set recSet2 = Server.CreateObject("ADODB.Recordset") 
    recSet2.Open strSQL2, dbConn 
End Function 

Function OpenDB() 
    Set dbConn = Server.CreateObject("ADODB.Connection") 
    dbConn.ConnectionTimeout = 30 
    dbConn.CommandTimeout = 120 
    dbConn.Open strConnectionString, strUserName, strPassword 
End Function 
+1

次に誰かがスクリプトを修正し「UPDATE ... ID =」 'との間の[連結演算子(https://msdn.microsoft.com/en-us/library/sx97884w)を除去する前に、これが働いている場合'と' recSet( "id") 'を呼び出す。しかし、文字列連結によるクエリの構築は、とにかく悪い練習です.b/cでは、コードを[SQLインジェクション](https://xkcd.com/327/)に開きます。 [prepared statement](http://stackoverflow.com/a/18619736)を使用し、 'recSet(" condition ")'と 'recSet(" id ")'の値をパラメータとして呼び出します。 –

+0

ファイルのTFSとタイムスタンプの両方は、これが7月24日以降に触れられていないことを示しています。 –

+0

その後、コードが機能していないか、7月24日以降に条件のどれも起動されていません。 –

答えて

0

数があるように見える、私は問題なく、次の作業を行っているため、更新コマンドは、有効である知っていますここでは問題が発生しますが、まずはタイムアウトの主な原因になるでしょう。私はrsRun2という関数を呼び出した直後に疑念を抱いていました。 rsRunrsRun2のためのあなたの定義の中であなたがOpenDBに電話をかけると、新しい接続毎回を開くこと

注意してください。 OpenDBを呼び出すと、すでに開いていた古いものを閉じることなく、その新しい接続で古いdbConnに置き換えます。これは、ループを繰り返すたびに新しいデータベース接続を開始しているため、データのサイズが大きくなると、接続要求がタイムアウトになるまで、それ以上受け入れません。

あなたは、本質的にちょうど2つの接続上の単一の呼び出しで実行するすべてのコマンドをバッチ処理することによって、問題を中心に作業しているので、あなたの書き換えバージョンが動作するという事実は、こののさらなる証拠です。あなたが唯一の接続を使用し、1 DBを使用していて、これ以上開かないので、もしそれが、同じ接続上で複数のコマンドを実行するために完全に大丈夫だと

注意。コード内のどこからでも開始を除いてOpenDBへの通話を削除するので、自分が行っていることを完全に制御することができます。

追加のアドバイスがあります。 Ansgar Wiechers氏は、あなたのSQLは潜在的にSQL Injectionに対して脆弱であるとしています。 ADOとパラメータ化されたクエリを使用してコードのセキュリティを向上させる方法を学ぶ必要があります。理論的には

*は、これらの古いオブジェクトがガベージコレクション結局のVBScriptによって得るが、これはすぐに、または対応する接続​​が正しくクローズされることを起こるという保証はありません。

+0

私はあなたが言っていることを聞いています。これらの機能は、このプロジェクトの前によく書かれていました。しかし、なぜそれはちょうど作業を停止するのだろうか?インジェクションに関しては、パラメータが渡されていないのでインジェクションが発生しないようにし、sprocから返されたID(プライマリキー、自動インクリメント)を参照して更新を呼び出します。 –

+0

私たちはすべてレガシーコードを愛しています!この問題は明らかに常に存在していましたが、データベーステーブルのサイズは、この問題が顕在化するだけの大きさになっている可能性が高いです。つまり、処理される行の数と、タイムアウトするまでに開いたままになっている接続の数が接続タイムアウト時間。 – BoffinbraiN

+0

SQLインジェクションに関して、その '条件'フィールドがデータベース内の整数である場合、この特定のケースは十分安全であるべきですが、原則として、SQLはこのように一緒につながれてはならないと言っています。 – BoffinbraiN