2009-08-13 5 views
2

Ich bekomme eine vertraute Timeout SqlException, wenn ich eine Menge neuer Datensätze schnell mit Subsonic ActiveRecord und Sql Server hinzufügen.Subsonic ActiveRecord - Verbindungen hängen beim Hinzufügen von vielen Datensätzen

Timeout abgelaufen. Der Timeout-Zeitraum ist vor dem Erhalt einer Verbindung vom Pool verstrichen. Dies kann aufgetreten sein, weil alle gepoolten Verbindungen verwendet wurden und max Pool Größe erreicht wurde.

Ich habe es geschafft, diese Frage mit dem folgenden einfachen Code-Block zu replizieren:

for (int i = 0; i < 1000; i++) 
    { 
     var address = new Address(); 
     address.City = "TEST"; 
     address.Save(); 
    } 

Der Code wird Datensätze hinzufügen, bis es 100 (die Größe Max Pool, wahrscheinlich nicht zufällig) erreicht, an dem Punkt es scheitert mit der obigen Ausnahme. Danach werden die Verbindungen für ungefähr 5-10 Minuten gehalten, währenddessen alle Versuche, die Datenbank zu verwenden, die obige Ausnahme ergeben.

Interessanterweise habe ich festgestellt, dass das Ausführen auf meinem lokalen Computer in VS (gleiche Codebasis für genau die gleiche Datenbankinstanz) der Code erfolgreich alle 1000 Datensätze hinzufügen. Vielleicht verlangsamt die Latenz zwischen hier und meinem Host die Datenbankaufrufe genug?

Vorausgesetzt, dass es lokal funktioniert, nehme ich an, dies ist kein Subsonic Problem direkt, aber gibt es einen Fehler, den ich mache oder irgendeine Art und Weise kann ich meinen Code oder Konfiguration ändern, um das schnelle Öffnen und Schließen von Verbindungen zu behandeln viele Datensätze seriell hinzufügen?

Antwort

4

Ich habe einen Perf-Test auf AR und SimpleRepo durchgeführt, der 100.000 Datensätze durchschlug und das Ding ziemlich hart schlug - Verbindungsprobleme sind wirklich der erste Stop beim Perf-Tuning.

Das sagte - wir hatten ein Problem in Pre-Release mit einem Leser offen gelassen werden :). Ich habe es vor ein paar Monaten repariert - kannst du bestätigen, dass du die neuesten Bits hast?

Auch - ja Latenz kann seltsam sein. Ich kenne die Details nicht, aber es sieht so aus.

+0

Dank für die Buchung hinzuzufügen hatte, habe ich es nicht wirklich träumte ein Problem mit Ihrem AR war. Ich benutze 3.0.0.3. Muss etwas mit dem Hosting-Provider oder ASP.NET-Konfiguration drüben sein. Mehr Seltsamkeit: Mit 100 Adds wird es erfolgreich und wiederholt abgeschlossen, sogar beim Laden der Seite, auf der die Add-in in 2 Browser-Fenstern gleichzeitig ausgeführt werden. Mit 101 fügt es jedes Mal fehl und sperrt alle Verbindungen für unbegrenzte Zeit. Verzögern nach jedem Hinzufügen, um Latenz zu simulieren und die Geschwindigkeit der Verbindung/Trennung zu reduzieren, hilft nicht. Das Ausführen eines .Find() - Befehls anstelle des Befehls .Add() hat den gleichen Effekt. –

+0

Ein weiterer Datenpunkt, der dies außerhalb von AR macht, scheitert nicht am Host: (Erstellen einer neuen sqlconnection, neuer sqlcommand, öffnender Conn, Ausführen des insert cmd als Textbefehl, disposed cmd, conn) innerhalb der Schleife scheint in Ordnung zu sein bis zu unendlichen Zählungen. Vielleicht ist es etwas darüber, wie AR die Verbindungen/Befehle, die mit der Konfiguration des Hosts in Konflikt stehen, freigibt/entfernt? –

1

Ich hatte das gleiche Problem mit MySQL. Durch das Instanziieren eines neuen aktiven Datensatzobjekts und den anschließenden Aufruf von save wurde eine Verbindung geöffnet, die nie geschlossen wurde.

Eine Lösung gefunden, die zu funktionieren scheint (Danke an kamsar http://github.com/subsonic/SubSonic-3.0/issues#issue/69) Offenbar liegt das Problem an einem nicht geschlossenen Reader ?!

Ändern der Linie 197 in SubSonicRepository.cs (3.0.0.3) zu "können (DbDataReader rdr = provider.ExecuteReader (Abfrage))" ( und Einwickeln der Verwendung in einem geeigneten Umfang auf etwa wie 218) scheint gelöst zu haben.

So sah der Code so aus und keine Verbindungsleck mehr !!!

  //var rdr = provider.ExecuteReader(query); 
      using (System.Data.Common.DbDataReader rdr = provider.ExecuteReader(query)) 
      { 
       if (rdr.Read()) 
        result = rdr[0]; 
       // repopulate primary key column with newly generated ID 
       if (result != null && result != DBNull.Value) 
       { 

        try 
        { 
         var tbl = provider.FindOrCreateTable(typeof(T)); 
         var prop = item.GetType().GetProperty(tbl.PrimaryKey.Name); 
         var settable = result.ChangeTypeTo(prop.PropertyType); 
         prop.SetValue(item, settable, null); 

        } 
        catch (Exception x) 
        { 
         //swallow it - I don't like this per se but this is a convenience and we 
         //don't want to throw the whole thing just because we can't auto-set the value 
        } 
       } 
      } 
0

InnerSphere hat die richtige Antwort. Ich konnte nicht abstimmen, weil ich den Rep-Score nicht habe und nicht herausfinden konnte, wie ich einfach auf seinen Post antworten/kommentieren sollte.

Die einzige Sache, die hinzuzufügen ist, wenn Sie den Code von GitHub ziehen, dieses Update ist bereits enthalten.

Keine Probleme nach dem Kompilieren und Verwenden der DLL aus dem Amtskode erstellt.

0

ich rdr.Close() direkt nach dem Ergebnis zu erhalten, d.h .:

if (rdr.Read()) 
    result = rdr[0]; 

rdr.Close(); 
Verwandte Themen