2016-12-22 1 views
0

Ich habe eine Konsole Batchanwendung, die einen Prozess enthält, der SqlDataAdapter.Fill (DataTable) verwendet, um eine einfache SELECT für eine Tabelle durchzuführen.Füllen (DataTable) ist erfolgreich zu testen, hängt in Produktion

private DataTable getMyTable(string conStr) 
    { 
     DataTable tb = new DataTable(); 
     StringBuilder bSql = new StringBuilder(); 
     bSql.AppendLine("SELECT * FROM MyDB.dbo.MyTable"); 
     bSql.AppendLine("WHERE LEN(IdString) > 0");     
     try 
     { 
      string connStr = ConfigurationManager.ConnectionStrings[conStr].ConnectionString; 
      using (SqlConnection conn = new SqlConnection(connStr)) 
      { 
       conn.Open(); 
       using (SqlDataAdapter adpt = new SqlDataAdapter(bSql.ToString(), conn)) 
       { 
        adpt.Fill(tb); 
       } 

      } 
      return tb; 
     }   
     catch (SqlException sx) 
     { 
      throw sx; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

Diese Methode wird synchron ausgeführt, und wurde erfolgreich in mehreren Testumgebungen über viele Monate des Testens laufen - sowohl, wenn sie von der Kommandozeile oder gestartet unter der Kontrolle eines AutoSys Job gestartet.

Bei der Produktion wurde der Prozess jedoch aufgehängt - bei der Fill-Methode so gut wie möglich. Schlimmer noch: Statt Zeitlimits auszulösen, hat es anscheinend neue Anfrage-Threads erzeugt und nach ein paar Stunden mehr als 5 GB Arbeitsspeicher auf dem Anwendungsserver verbraucht. Dies wirkte sich auf andere aktive Anwendungen aus und machte mich sehr unpopulär. Es wurde keine Ausnahme ausgelöst.

Die Connection String ist ungefähr so ​​schlicht wie sie kommen.

"data source=SERVER\INSTANCE;initial catalog=MyDB;integrated security=True;" 

Entschuldigt, wenn ich die falschen Begriffe verwenden in Bezug auf was die SQL DBA unten angegeben, aber wenn wir setzen auf dem SQL Server eine Spur hatte, zeigte er die ID-Anwendung (unter denen der AutoSys Job ausgeführt wurde) akzeptiert als gültiges Login. Der Server schien dann die SELECT-Abfrage zu verarbeiten. Es gab jedoch keine Antwort zurück. Stattdessen ging es in einen Status "Warten auf Befehl". Der Anfrage-Thread schien einige Minuten geöffnet zu sein und verschwand dann.

Der DBA sagte, dass es keine Anzeichen für einen Deadlock gäbe, aber dass er in Echtzeit überwachen müsste, um festzustellen, ob eine Blockierung vorliegt.

Dies tritt nur in der Produktionsumgebung auf; In Testumgebungen reagierten die SQL Server immer in weniger als einer Sekunde.

Die AutoSys Application ID ist keine neue - es wurde seit mehreren Jahren mit anderen SQL-Servern verwendet und hatte keine Probleme. Der DBA führte sogar die SELECT-Abfrage manuell auf dem Produktions-SQL-Server aus, der als diese ID angemeldet war, und er reagierte normal.

Wir konnten das Problem nicht in einer nicht produktiven Umgebung reproduzieren und zögern, es in der Produktion auszuführen, ohne dass ein Serveradministrator bereitsteht, um den Prozess zu beenden. Unsere Sicherheitsanforderungen beschränken den Zugriff auf die Protokolle und Prozesse des View Servers, und normalerweise muss ich einen anderen Spezialisten hinzuziehen, um sie für mich zu betrachten.

Wir müssen dieses Problem früher oder später lösen. Die Menge an Daten, die wir uns ansehen, ist derzeit nur ein paar Zeilen, wird aber in den nächsten Monaten zunehmen. Von dem, was passiert, ist meine beste Schätzung, dass es Kommunikation und/oder Sicherheit zwischen dem Anwendungsserver und dem SQL-Server beinhaltet.

Alle zusätzlichen Ideen oder Gegenstände zu untersuchen sind willkommen. Danke an alle.

+0

Bei großen Datenbanken kann die Abfrage in VS lange dauern. Verhindere das Hängen Ich benutze einen BackGroundWorker, um zu arbeiten. Anstatt die Datenbank direkt abzufragen, benutze ich cmd.exe, welches eine ausführbare Befehlszeile ist (kommt mit SQL Server), um eine Abfrage durchzuführen und eine CSV-Datei mit Ergebnissen zu erzeugen. Lesen Sie dann die Ergebnisse in der VS-Anwendung. Ich benutze cmd.exe von C# mit einer Prozessklasse aus einem backgrounderworker. – jdweng

+0

@jdweng: Ich denke, das sind einige gute Punkte. Wenn es eine einfache select-Anweisung ist, führen Sie es aus dem sql-Befehlszeilentool aus und schließen Sie die Möglichkeit aus, dass in der Anwendung etwas nicht stimmt. Wie groß ist der Tisch? Sie können die Auswahl mit TOP 1000 ausführen, um sicherzustellen, dass die Ergebnisdaten wie erwartet sind. Das Schreiben von Daten in CSV klingt für mich zum ersten Mal seltsam, aber mit wirklich großen Daten kann es ein Weg sein. –

+0

Mit meiner Anwendung dauerte die sqlcmd.exe 30 Minuten oder länger auf einer 10 GB-Datenbank. Es dauerte Stunden als eine Abfrage in C#. Und meine Fenster für die Anwendung hängen, während die Abfrage ausgeführt wurde. Die einzige Methode, die ich fand, um die Ergebnisse von sqlcmd.exe in C# zu bekommen, war mit einer CSV-Datei. – jdweng

Antwort

0

Obwohl es durch einige seltsame Berechtigungen/ADO verursacht werden kann.NET genannten Themen wie @user1895086, würde ich dennoch ein paar Dinge noch einmal nachprüfen würde empfehlen:

  1. Stellen Sie sicher, dass Abfragen in Ihrer App manuell von DBA und ausgeführt laufen gleich sind - entweder hart codieren sie oder zumindest Protokollieren Sie kurz vor dem Ausführen. Es ist besser als Nachsicht.
  2. Versuchen Sie, nur wenige Zeilen auszuwählen - es ist immer eine gute Idee, nicht die gesamte Tabelle auszuwählen, wenn Sie es vermeiden können, und in unserem Fall SELECT TOP 1 (oder 100) Abfrage möglicherweise solche Probleme nicht aufweisen. Vielleicht gibt es nur viel mehr Daten als Sie denken und ADO.Net versucht nur pflichtbewusst alle diese Zeilen zu laden. Oder vielleicht nicht.
  3. Versuchen Sie SqlDataReader, um sicher zu sein, dass SqlDataAdapter keine Probleme verursacht - ja, es verwendet den gleichen DataAdapter internally, aber wir würden mindestens diese zusätzlichen Operationen aus einer Liste von Verdächtigen auszuschließen.
  4. Versuchen Sie, eine Hand auf dem Dump mit diesen 5 GB Speicher zu bekommen - analyzing memory dumps ist keine triviale Aufgabe, aber es wird nicht zu schwer zu verstehen, was diese heftigen Stücke Speicher zu essen ist. Weil ich irgendwie bezweifle, dass ADO.NET einfach viele zusätzliche Objekte ohne Grund spawnt.
+0

Ich akzeptierte diese Antwort aufgrund des Vorschlags, die Abfrage zu vergleichen, die die Anwendung gegen das gesendet hat, was von dem SQL Server empfangen wurde. Es trat tatsächlich in einer Methode auf, die nach der obigen ausgeführt wurde, und mit Entity Framework auf einen anderen DB zugreift. Ein LINQ-Ausdruck sollte bewirken, dass EF höchstens einige hundert Zeilen auswählt. Stattdessen versuchte die von LINQ konvertierte Abfrage, eine gesamte 1,7 Millionen Ringtabelle in den Speicher zu laden, und zwar in drei separaten Anforderungs-Threads. – 66AndStillLearning

1

Dies kann an Berechtigungen gebunden sein. SQL Server führt einige seltsame Dinge aus, anstatt manchmal eine richtige Fehlermeldung zu geben.

Mein Vorschlag, und das könnte Leistung sowieso verbessern, ist, eine gespeicherte Prozedur auf der Serverseite zu schreiben, die die Auswahl ausführt, und die gespeicherte Prozedur aufrufen. Auf diese Weise kann der DBA sicherstellen, dass Sie ordnungsgemäß auf die gespeicherte Prozedur zugreifen können, ohne direkten Zugriff auf die Tabelle zu gewähren, wenn aus irgendeinem Grund blockiert wird, und Sie sollten einen leichten Leistungsschub sehen.

+1

Während ich mit fast allem hier einverstanden bin, warum glauben Sie, dass eine gespeicherte Prozedur eine Leistungssteigerung gegenüber einer Ad-hoc-Abfrage bietet? –

+0

Das geht in eine Debatte ein, die zwischen Programmierern tobt und seit einiger Zeit besteht, gerade jetzt, wo das Fenster eingeengt wird. Es gab eine Zeit, in der es einen viel größeren Unterschied machte, aber jetzt basiert es mehr auf der Umgebung. Dennoch erhöht die Verwendung von gespeicherten Prozeduren typischerweise die Leistung sehr geringfügig (da es dem DBMS mehr Freiheit gibt, die Abfrage zu optimieren. Warum? Gründe. Ich bin kein DBA), während einige Fallstricke verhindert werden, die bei Verwendung von Ad-hoc auftreten können Es ermöglicht auch Änderungen an den Abfrageparametern, ohne Code erneut kompilieren und erneut an die Benutzer bereitstellen zu müssen. – CDove

+0

Es verbessert nicht die Leistung. Eine Ausführung wird seit sql 6.5 (vor fast zwei Jahrzehnten) für eine Ad-hoc-Abfrage wie eine gespeicherte Prozedur kompiliert und zwischengespeichert. Ich sage nicht, dass ich Ad-hoc-Abfragen an gespeicherte Prozeduren bevorzuge. Im Gegenteil, ich bin für alle gespeicherten Procs und würde aus den meisten Gründen, die Sie gerade erwähnt haben, niemals meine eigene Ad-hoc-Abfrage schreiben. Es ist jedoch ein langer Fehler, dass eine gespeicherte Prozedur schneller ist als eine Ad-hoc-Abfrage. Es ist einfach nicht wahr. Lesen Sie diesen Artikel zu gespeicherten Procs. https://sqlperformance.com/2013/05/t-sql-abfragen/another-argument-for-stored-procedures. –

Verwandte Themen