2017-12-20 1 views
1

Wir haben eine Datei, die jede Nacht läuft, die seit Monaten ohne Probleme funktioniert hat. Plötzlich führt es zu Abfrage-Timeout-Fehlern. Ein schneller Trace zeigt mir, dass es jedes Mal bei sekundären Abfragen (Updates) versagt.Update Abfrage innerhalb Do NotEOF Zeitüberschreitung

Eine sehr allgemeine Zusammenfassung der Codeausführung:

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) 

Dies wurde für Monate und Monate am Ende in Ordnung zu arbeiten, und nicht jetzt jedes Mal, dass einen des Updates trifft.

Edit: Ich weiß, dass die Update-Befehle gültig sind, denn ohne Frage die folgenden Werke zu tun:

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) 

Edit 2: Einschließlich der Funktionen aufgerufen:

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

Wenn dies vorher funktioniert hat, dann hat jemand das Skript modifiziert und den [Verkettungsoperator] (https://msdn.microsoft.com/en-us/library/sx97884w) zwischen '" UPDATE ... id = "entfernt 'und' recSet ("id") '. Das Erstellen von Abfragen nach String-Verkettungen ist jedoch ohnehin eine schlechte Übung, b/c öffnet den Code für [SQL injection] (https://xkcd.com/327/). Verwenden Sie eine [prepared statement] (http://stackoverflow.com/a/18619736) und rufen Sie sie mit den Werten von 'recSet (" condition ")' und 'recSet (" id ")' als Parameter auf. –

+0

Sowohl TFS als auch der Zeitstempel der Datei zeigen, dass dies seit dem 24. Juli nicht mehr berührt wurde. –

+0

Dann hat entweder der Code nicht funktioniert oder keine der Bedingungen wurde seit dem 24. Juli ausgelöst. –

Antwort

0

Es gibt ein paar zu sein scheinen Probleme hier, aber ich werde zuerst auf die Hauptursache der Timeouts kommen. Ich hatte meinen Verdacht, sobald ich Aufrufe an eine Funktion namens rsRun2 sah.

Beachten Sie, dass in Ihrer Definition für rsRun und rsRun2 Sie einen Anruf zu OpenDB machen und öffnen Sie eine neue Verbindung jedes Mal. Der Aufruf OpenDBersetzt die alte dbConn mit dieser neuen Verbindung, ohne die alte zu schließen, wenn eine bereits geöffnet war. Das bedeutet, dass Sie bei jeder Iteration über Ihre Schleife neue Datenbankverbindungen öffnen. Wenn Ihre Daten größer werden, verlieren Sie im Wesentlichen * mehr und mehr Verbindungen, bis diese Verbindungsanforderungen zu einer Zeitüberschreitung führen, weil der Datenbankserver gewonnen hat. t akzeptiere nicht mehr.

Die Tatsache, dass Ihre umgeschriebene Version funktioniert, ist ein weiterer Beweis dafür, da Sie das Problem im Wesentlichen umgehen, indem Sie alle Befehle in einem einzigen Aufruf auf nur zwei Verbindungen aufteilen.

Beachten Sie, dass es vollkommen in Ordnung ist, mehrere Befehle auf derselben Verbindung auszuführen. Wenn Sie also nur eine DB verwenden, verwenden Sie eine Verbindung und öffnen Sie keine mehr. Entfernen Sie alle Anrufe in Ihrem Code von OpenDB bis auf den Anfang, damit Sie die volle Kontrolle darüber haben, was Sie tun.

Jetzt für einige zusätzliche Ratschläge. Wie Ansgar Wiechers sagte, ist Ihr SQL möglicherweise anfällig für SQL-Injection, insbesondere wenn Sie Ihren Datenbankcode anderswo schreiben. Sie sollten sich einmal überlegen, wie Sie die ADO und parametrisierten Abfragen verwenden können, um die Sicherheit in Ihrem Code zu verbessern.

* Theoretisch werden diese alten Objekte schließlich von VBScript gesammelt, aber es gibt keine Garantie dafür, dass dies schnell geschieht oder dass die entsprechende Verbindung ordnungsgemäß geschlossen wird.

+0

Ich höre was du sagst. Diese Funktionen wurden lange vor meiner Zeit in diesem Projekt geschrieben. Warum sollte es einfach aufhören zu arbeiten? In Bezug auf die Injektion wäre es in diesem Fall unmöglich, dass eine Injektion stattfindet, da keine Parameter übergeben werden, und die Aktualisierungen werden durch Referenzieren der zurückgegebenen ID (Primärschlüssel, automatisches Inkrement) von dem Sproc aufgerufen? –

+0

Wir alle lieben Legacy-Code! Nun, das Problem war eindeutig immer da, aber es ist wahrscheinlich, dass die Größe Ihrer Datenbanktabelle gerade groß genug wurde, dass dieses Problem sichtbar wurde, dh die Anzahl der Zeilen, die verarbeitet wurden, und die Anzahl der Verbindungen, die vor dem Zeitlimit offen blieben Verbindungs-Timeout-Zeit – BoffinbraiN

+0

In Bezug auf SQL-Injection, wenn das 'Bedingung' Feld eine ganze Zahl in der Datenbank ist, dann sollte dieser spezielle Fall sicher genug sein, aber ich sage nur, dass SQL im Prinzip nicht so zusammengereiht werden sollte. – BoffinbraiN

Verwandte Themen