| 

.NET C# Java Javascript Exception

2
Hallo zusammen,
ich habe folgendes Problem derzeit:
Ich habe Laptops (Clients) auf denen per Merge Replikation eine verkleinerte Version der Hauptdatenbank aus einer Zentrale landet. Auf den Clients läuft der SQLExpress 2008 R2.

Die Clients werden natürlich immer wieder Heruntergefahren und irgendwann später wieder gestartet.
Die Anwendung, welche auf die lokale SQLExpress Datenbank zugreift, läuft beim Starten allerdings in TimeOuts, da die ersten Abfragen auf die Datenbank zu lange brauchen.

Ich habe das ganze einmal mit dem Management Studio versucht nach zu vollziehen. Es gibt bei uns einige gespeicherte Prozeduren, welche Joins über 5-6 Tabellen machen, welche recht groß sind (160.000 Einträge und mehr), diese Abfragen brauchen bei der ersten Ausführung bis zu 4 Minuten und man hört ganz deutlich wie die kleine Festplatte des Laptops am rattern ist ;)
Bei jeder weiteren Abfrage danach dauert es dann aber nur noch wenige Sekunden.
Starte ich den Dienst neu, dauert die Abfrage wieder 4 Minuten.
Ich nehme mal an (bin mir da aber auch nicht sicher) das der Server bei den ersten Abfragen auf die Tabellen diese speziell vorbereitet und in eine Art Cache lädt.
Die Abfrage um die es hier geht, beinhaltet laut Ausführungsplan, nur Clustered Index Seeks oder Key Lookups, das Problem scheint mir nur in der Menge der Einträge zu liegen (die ich auch nicht verkleinern darf, da die Clients diese Datenmenge brauchen).

Als Lösungsansatz hatte ich die Idee gehabt einfach ein Startup Script zu schreiben, welches beim Rechner Start dann einfach in der lokalen Datenbank ein paar dieser Prozeduren aufruft. Jedoch bin ich der Meinung das es doch sicher bessere Möglichkeiten gibt. Gibt es den eine Möglichkeit auf dem SQLExpress da für mehr Performance zu sorgen?

Gleich vorweg: Die Datenbank ist sauber modelliert und strukturiert. Es wurden sinnvolle Verknüpfungen, Indexe, etc... gesetzt. An der Datenbank Struktur kann ich nur schwer Änderungen vor nehmen, da die Datenbank unter Replikation steht, ich kann also eigentlich nur den Inhalt anpassen, bzw die Client Server konfigurieren.

Vllt. weiß ja hier jemand Rat, oder kann mir zumindest einmal erklären, warum das so langsam ist, liegt das an der Express Edition oder wäre das auch bei einem richtigen MS SQL Server so, der gerade frisch gestartet wurde?

Vielen Dank für eure Hilfe
Chris

Edit - weitere Details (IO und Time Statistics):

Ausführungsplan: http://img10.imageshack.us/img10/6022/abfrage.png

Okey herrausgekommen ist dabei das hier:
SQL Server parse and compile time: 
CPU time = 31 ms, elapsed time = 546 ms.

SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.

(0 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PERSON'. Scan count 0, logical reads 819522, physical reads 7774, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'ANTRAG'. Scan count 10, logical reads 410004, physical reads 12625, read-ahead reads 214, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CATALOGS'. Scan count 1, logical reads 2, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'KONTAKT'. Scan count 0, logical reads 2, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 8141 ms, elapsed time = 207828 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.

SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.


PERSON umfasst ca 126.000 Datensätze, ANTRAG hat ca. 136.000 Datensätze.
Führe ich die Abfrage nocheinmal aus kommt es zu diesem Ergebnis:
SQL Server parse and compile time: 
CPU time = 0 ms, elapsed time = 0 ms.

SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.

(0 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PERSON'. Scan count 0, logical reads 819522, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'ANTRAG'. Scan count 10, logical reads 410004, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CATALOGS'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'KONTAKT'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 2500 ms, elapsed time = 2500 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.

SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
10.02.2011
chris.net 33 1 5
Floyd 14,6k 3 9
Kannst Du uns die Abfrage posten?
Marvin Steppat 14.02.2011
6 Antworten
2
Hi Chris,

die Startup-Scripts die dir vorgeschwebt haben sorgen dafür das die Datenbank von der Festplatte in den Speicher geladen wird was bei großen Datenbanken (mehre Millionen Datensätze) durchaus sinnvoll ist.

Das zweite ist die Laufzeit deiner Statements. Hier solltest du mal den Ausführungsplan anschauen. Einmal in der Version nach dem Server-NeuStart und einmal normal.
Hier siehst du dann die Sahwächen und bekommst Optimierungsvorschläge (z.B. fehlende Indexe).

Generell solltest du das Thema Indexe in deiner Datenbank nochmal überdenken. Hier scheint es ein Problem zu geben wenn du bereits Probleme bei 0,16M Datensätzen hast. Der Ausführungsplan wird dir dabei hilfreich sein (überall wo Index-Scan und nicht Index-Seek gemacht wird, sollte man prüfen).
10.02.2011
Floyd 14,6k 3 9
2
Der Abfrageplan zeigt, zwei Dinge: 1. Nur seeks 2. Angeblich extrem wenige Rows. Du hast folglich ein Statistikproblem: Der Optimizer denkt, deine Tabellen sind fast leer, weshalb die loop joins auch optimal wären. Führe folgendes Statement aus:

EXEC sp_updatestats

Und berichte von den Ergebnissen!
14.02.2011
Marvin Steppat 4,0k 1 4 8
Das sollte automatisch passieren es sei den jemand war so intelligent und hat dies ausgestellt.
Floyd 14.02.2011
Jedenfalls nicht wissentlich, aber ich denke man muss das schon explizit abstellen und die SQLExpress installationen auf den NBs sind ganz normale installationen ohne irgendwelche großen Einstellungen
chris.net 14.02.2011
Naja, ein versuch schaden bestimmt nicht ;)
Floyd 14.02.2011
Wenn Du uns die Abfrage schickst, sieht man vielleicht, warum so schlechte Schätzungen vom Optimizer produziert wurden. Vielleicht sind die where-Bedinungen für den nicht durchschaubar.
Marvin Steppat 14.02.2011
Die Abfrage steht im Ausführungsplan im Klar-Text drin ;)
Floyd 14.02.2011
Jo... Was verbirgt sich denn hinter der Prozedur "ACM.udf_Antragsvertraege(a.RecordID)"?
Marvin Steppat 14.02.2011
Nichts, das Weglassen dieses Funktionsaufrufes führt zu keiner Veränderung im Abfrageverhalten oder anders gesagt, das ist nicht der Bösewicht ;)
chris.net 14.02.2011
Marvin wird schon richtig liegen. Die Statistiken sollten das Problem sein. Das würde auch begründen warum der geschätzte Ausführungsplan nicht mal ansatzweise mit dem Ergebnis der IO Statistiken übereinstimmt.
Floyd 14.02.2011
Nun ich werd Mittwoch wieder an zu mindest eines der Notebooks kommen, auf denen die Probleme aufgetreten sind, ich werde dann dort einmal das sp_updatestats ausführen.
chris.net 14.02.2011
Wenn es Mittwoch immer noch nicht klappt, dann tweete ich diese Frage. Das Problem muss doch zu knacken sein ;-)
Marvin Steppat 14.02.2011
Wenns Mittwoch immer noch nicht klappt, dann schick mir den Laptop .. du bekommst dann das Ergebnis und ich höker selbigen dann bei eBay (gegen eine Zahl von 500 € auch mit formatierter Festplatte). :P
Floyd 14.02.2011
Hmm wird wohl nichts mit neuem Laptop, es geht inzwischen :) Das Problem ist wohl das durch die Merge Replikation die index stats durch einander kommen, sobald ich updatestats ausgeführt hatte waren die Abfragen wieder schön schnell. Jedoch muss ich updatestats nach jedem abgleich der daten mit der zentrale erneut ausführen, da jeder merge abgleich die index stats wieder leicht durcheinander zu bringen scheint.

Danke nochmal an alle für euere Hilfe ;)
chris.net 16.02.2011
1
Hallo Floyd,
danke für deine Antwort.
Ich habe mir den Ausführungsplan angeschaut, ich kann dort allerdings keine Probleme Feststellen.

Ich habe den Plan einmal hochgeladen: http://img10.imageshack.us/img10/6022/abfrage.png

Dort sind nur Index-Seeks, aber eben über viele Tabellen mit vielen vielen Einträgen.

Kann man den Express nicht anweisen da irgendwelche Optimierungen vor zu nehmen wenn der Dienst startet?
11.02.2011
chris.net 33 1 5
1
Also am Ausführungsplan liegt es nicht wobei ich jetzt natürlich nicht die ToolTips sehe :D. Jedenfalls sieht der gut soweit aus. Bei 0.16M Datensätzen wirst du etwa 250-300 MB Arbeitsspeicher brauchen. Mach mal folgendes. Klick mal in dein Query-Fenster mit der Rechten Maustaste rein und stell unter "Query Options"->"Execution"->"Advanced" die Optionen "SET STATISTICS TIME" und "SET STATISTICS IO" an. Starte deine SQL-Server neu und führ das Query erneut aus. Jetzt erscheint im "Meldungs"-Fenster die Ausgabe wie lange er für welche Aktion gebraucht hat.
Floyd 11.02.2011
1
Damit ist gemeint: Compile-Time, IO-Zugriff und benötigte Zeit, Execution-Time.
Zweite Frage. Tritt das Problem NUR beim nach einem Neustart des SQL-Servers auf bzw. wenn du ihn eine weile nicht benutzt hast (Stichwort Auslagerung).
Wenn ich das richtig verstanden habe ist in der Konfiguration der Arbeitsspeicher und die Festplatte hier das Limitierende Kriterium.
Floyd 11.02.2011
1
Also folgende 2 Probleme konnten identifiziert werden.

1. Deine Festplatte ist das Problem. Es werden etwa 10.000 Festplattenzugriffe getätigt. Da du in deinem Laptop nur eine Festplatte drin hast (und diese somit auch von anderen Prozessen verwendet wird) und Notebook-Festplatte eh. etwas langsamer sind gehe ich mal von 18-20 ms pro Read aus wodurch du auf die 207s Execution kommst. Davon gehen nochmal 0,5 Sekunden fürs Compilieren und Optimieren weg was aber nicht ins Gewicht fällg. Die Anzahl der "read-ahead reads" ist sehr gering weswegen ich empfehle mit dem Tool Contig von Sysinternals (Microsoft) das Datenbank-File zu defragmentieren. Das sollte den ganzen Lesevorgang beschleunigen.

2. Deine Indexe sind nicht optimal. Nach einer Optimierung sollten diese die Anzahl der Lesezyklen auf der Festplatte deutlich verkleinern. Sollte also der Schritt 1 (Defragmentieren des Datenbankfiles) nicht das gewünschte Ergebnis bringen , mach bitte folgendes.
Wiederhole bitte den Vorgang von eben nochmal, lass dir die Ausführungspläne anzeigen und speichere diese als XML ab. Schick Sie mir dann bitte und ich kann Sie bei mir wieder einlesen und sie betrachten. Dann kann ich dir ein paar konkrete Optimierungsvorschläge machen.
11.02.2011
Floyd 14,6k 3 9
1
Okey das Defragmentieren hat wirklich viel gebracht, danke dafür! Die Abfragezeit ist nun von 4min auf 2min runter, aber 2min sind immer noch zu lange, da der Timeout bereits nach 30sek im Programm auftritt.

Ich hab hier den Ausführungsplan als XML, jetzt ma ne blöde Frage: Wie schicke ich den dir hier? ;)
chris.net 11.02.2011
Sehr gut. Da ist das schon mal deutliche Verbesserung.
Lad ihn doch als Rar oder Zip Archiv bei http://www.file-upload.net/ hoch und poste hier den Link und das Archiv-Passwort.
Floyd 11.02.2011
Danke (hier fehlt noch eine kleine Datei Upload Funktion...)
http://www.file-upload.net/download-3205779/Execution-plan.rar.html PW: codekicker
chris.net 11.02.2011
Problem, das ist nur der "geschätze Ausführungsplan". Ich brauch aber den echte ;)
Floyd 11.02.2011
Noch ne alterantiv kannst du auch den CommandTimeout in deinem Programm auf 2 Minuten setzten. Ich weiß leider nicht welche Programmiersprache du verwendest.
Floyd 11.02.2011
ich nutze c#, aber das ist ja nicht was ich meinem benutzer antun kann, das der dann 2min warten muss. Ich kann die den 'echten' Ausführungsplan erst Montag geben, ich hab schon Feierabend ;) Aber vielen lieben Dank ersmtal bis hier hin, ich melde mich dann Montag
chris.net 11.02.2011
0
Edit Floyd: In Hauptbeitrag verschoben da diese Information der Konkretisierung der Frage / des Problem nützlich sind.
11.02.2011
chris.net 33 1 5
Floyd 14,6k 3 9
0
Nun inzwischen hat sich einiges getan. Ich musste inzwischen das Notebook austauschen (da der Mitarbeiter von dem ich das NB hatte dieses selbst wieder braucht), habe allerdings ein Baugleiches Modell bekommen.

Das Fazinierende an diesen NB ist, das dort quasi alles Funktioniert. Die Abfrage braucht das erste Mal ca. 5sek, danach unter 1sek. Ich habe einmal den tatsächlichen Abfrageplan hier hochgeladen.

Was ich nicht verstehe (das Problem hatte ich schon bei der inbetriebnahme gehabt) das auf manchen NBs die abfragen schnell ausgeführt werden, auf andern wiederrum ewig brauchen. Und das obowlh sie baugleich sind. Auch interessant ist das Ausgabefenster der Abfrage (gleiche Abfrage wie bei dem andern NB):
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 63 ms, elapsed time = 812 ms.

SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.

(0 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'ANTRAG'. Scan count 1, logical reads 3, physical reads 3, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PERSON'. Scan count 1, logical reads 6, physical reads 6, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'KONTAKT'. Scan count 0, logical reads 2, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

SQL Server Execution Times:
CPU time = 15 ms, elapsed time = 625 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.

SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.

Hier führt er viel weniger logical reads und physical reads aus. Ich verstehe nur nicht warum sich diese so stark unterscheiden. Gleiche Express Version, gleiche Abfrage, gleiche DB und gleiche NBs.

Ich versteh die SQL Welt nimmer :(
14.02.2011
chris.net 33 1 5
Sehr gute Frage. Ich würde vermuten des die Index nicht falsch, sondern nur fragementiert waren (das hat nichts mit der Dateifragementierung zu tun). Richtig testen könnte man das nur wenn du das alte Notebook nochmal in die Finger bekommst und ein Index-Rebuild anwirfst.
Floyd 14.02.2011

Stelle deine Performance-Frage jetzt!