Announcement

Collapse
No announcement yet.

Timeout bei UPDATE-Statement

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Timeout bei UPDATE-Statement

    Hi,

    Es geht um eine VB.NET-Datenbankanwendung, die auf einen SQL-Server zugreift. Ich weiß jetzt nicht, in welchem Forum das besser aufgehoben ist, für die Fehlerursache aber vermutlich eher hier...

    In letzter zeit bekommen wir immer häufiger Timeouts, wenn aus meiner Applikation heraus ein Datensatz gespeichert wird (das Programm stellt einen "UPDATE Tabelle With (ROWLOCK) SET feld1='xxx', feld2=NULL, feld3='abc', feld4=y,..., feld27='xyz WHERE ID=a' String zusammen und schickt den an die Datenbank).

    Ich erhalte eine Fehlermeldung "Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding". Unsere IT-Abteilung meint, das Netwerk wäre in Ordnung, und umgestellt hätten sie in letzter Zeit auch nichts, einen signifikanten Anstieg der Zugriffsrate oder der Datenbank (dass die Datenbasis einfach zu groß ist und der Server deshalb so lange braucht) ist auch nicht in dem Maße nachvollziehbar. Gegenseitige Sperren sind auch unwahrscheinlich, da von der Software schon sichergestelltwird, dass keine 2 Personen auf den gleichen Datensatz schreibend zugreifen, und Lesezugriffe immer ein WITH (NOLOCK) mitbekommen.

    Die Fehlersuche kann also noch etwas dauern. Vielleicht weiß ja hier jemand, woran es noch liegen könnte

    Jedenfalls dachte ich daran, bis der Fehler gefunden und behoben ist, bei einer Exception aufgrund eines Timeouts einfach mit einem längeren Timeout nochmal nachzufragen. Kann ich den überhaupt für ein einzelnes SqlCommand umsetzen, und wenn ja, in welcher Eigenschaft, oder ist das eine Einstellung des Servers, auf die ich als anfragende Applikation eh keinen Einfluss habe?

    Gruß
    Martin Dietz

  • #2
    natürlich kann man in .NET einem einzelnen Kommando einen Timeout-Wert mitgeben, etwa so:

    cmdS = New SqlCommand(....)
    cmdS.CommandTimeout = 300

    ... wäre dann für 300 Sekunden.

    Abgesehen davon würde ich das WITH (ROWLOCK) mal weglassen und den Server entscheiden lassen. Interessant wäre auch, vorher mit einem

    SELECT COUNT(*) from Tabelle WHERE .....

    festzustellen, wieviele Datensätze betroffen sind. Wenn da zB mit einer eindeutigen ID zugegriffen wird und genau 1 Record betroffen ist und trotzdem dieser Fehler kommt, dann gibt es definitiv irgendein Problem (zB 50 Millionen Datensätze in der Tabelle und ID ist weder PK noch indiziert, sodass ein Tablescan erforderlich wird). Handelt es sich aber um ein paar tausend Datensätze kann es sein, dass das ROWLOCK die Performancebremse wird.

    bye,
    Helmut

    Comment


    • #3
      Erstmal Danke für die Antwort. Ich hab das inzwischen umgesetzt. Um das ursprüngliche ExecuteNonQuery war ja schon ein try-catch-Block. Den habe ich so erweitert, dass er explizit eine SqlException abfängt und auf Timeout prüft (da war noch ein bisschen Googlen notwendig... ex.Number=-2, das ist aber auch nirgends dokumentiert...), und in einem erneuten Try-Catch innerhalb des Catch-Blocks es mit einem cmd.CommandTimeout=180:cmd.ExecuteNonQuery nochmal probiert.

      Ansonstensieht es so aus, dass ich nur in den seltensten Fällen SQL-Anweisungen erzeuge, die mehr als einen Datensatz auf einmal umsetzen, und das sind dann Aktionen, für die der Anwender Administrator-Berechtigungen benötigt, oder nur in geringen Fällen mehr als 20 Datensätze betrifft (So etwas wie im großen Stil Aufträge als verbucht kennzeichnen oder ähnliches), und dann sind es maximal 5 Spalten. UPDATE und INSERT-Anweisungen, die durch einen Normalanwender der Software verursacht werden, sind also nur in Ausnahmen nicht auf Einzeldatensätzen.

      Da wo die Fehler aufgetaucht sind (bzw., wo mir die Fehler gemeldet wurden), sind es Speicherungen eines einzelnen Datensatzes gewesen, auf den über seinen Primärschlüssel zugegriffen wird, und der ist laut EnterpriseManager als Identität=Ja, IDStartwert=1, ID-Schrittweite=1 angelegt, dann sollte er auch indiziert sein. Es sind halt momentan 331525 Einträge in der Tabelle, und die hat 44 Spalten, aber das sind halt auch keine Größenordnungen, mit denen der SQL-Server nicht umgehen könnte. Das Rowlock auf einem einzelnen Datensatz sollte kein Performance-Problem sein, dient im Grunde genommen nur der Sicherheit, also dass der Anwender bei paralleler Bearbeitung gewarnt wird und nicht die Änderungen eines Kollegen überschreibt oder beim gleichzeitigen Lesen sich die Datenbank nicht verhakt. Ein Fehlschlagen aufgrund einer Sperre sollte aber doch unter einem anderen Fehler zurückgemeldet werden, und nicht als Timeout, oder irre ich mich da?

      Ich werde es jetzt mit dieser Änderung weiter beobachten auch wenn ich aufgetretene Timeouts nicht mitprotokolliere, ich doktore halt nur ungern an den Symptomen herum, wenn die Ursache behebbar ist...

      Comment


      • #4
        Nur so als Info: wenn ein Feld als IDENTITY angelegt wird, muss es deswegen noch lange nicht indiziert sein - also kontrollieren, ob wirklich ein Index draufliegt

        bye,
        Helmut

        Comment

        Working...
        X