Code Optimieren?
-
Hallo Jung,
wie könnte ich folgenden iterativen Code optimieren?
using (SqlCeDataReader reader = cmd.ExecuteReader()) { Querytimer.Stop(); _eventLogger.Log( EventClass.System, this.GetType().Name, "Query Execution time: '" + Querytimer.ElapsedMilliseconds.ToString() + "'"); Querytimer.Reset(); Querytimer.Start(); byte[] rawbytes; while (reader.Read()) { short len = reader.GetInt16(4); double time = (double)reader.GetDouble(2); uint tagid = (uint)(short)reader.GetInt16(1); if (reader.GetBytes(3, 0, rawbytes = new byte[len], 0, len) != len) continue; tmp.Add( new KeyValuePair<DateTime, TagLoggingRecord>( DateTime.FromOADate(time), new TagLoggingRecord() { TagID = tagid, Data = rawbytes })); } }
Die Eigentliche Arbfrage geht schnell, aber das mapping in mein TagLoggingRecord dauert bei ca 30.000 datensätzen ca. 10 sek. könnte ich da noch was optimieren??
grüße
-
Ehm, ist das nicht C#?
Simon
-
Ja sorry bin verrutscht...
-
Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum MFC (Visual C++) in das Forum C# und .NET verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
NullBockException schrieb:
Die Eigentliche Arbfrage geht schnell, aber das mapping in mein TagLoggingRecord dauert bei ca 30.000 datensätzen ca. 10 sek. könnte ich da noch was optimieren
Dazu hättest du uns sagen müssen was tmp ist.
-
tmp is ne liste...
List<new KeyValuePair<DateTime, TagLoggingRecord>> tmp=....
wenn ich aber den tmp.Add(...) Part auskommentiere, ist trozdem noch gleich schlecht.
Liegt wohl an den DB reader funktionen. Die sind saumässig langsam
-
Dann schmeiß den DB reader doch raus und hau dir LINQ to SQL Klassen rein.Eventuell verschnellert das die Performance
-
@Firefighter: LINQ to SQL is wenn überhaupt langsamer als "direkt".
@NullBockException: Die "Abfrage" ist nicht notwendigerweise komplett abgeschlossen, wenn du den DataReader zurückbekommst. Den bekommst du nämlich schon, wenn die erste Zeile verfügbar ist. Das geht manchmal sehr schnell, während SQL Server noch die restlichen Zeilen zusammenkratzt - was u.U. recht lange dauern kann.
Mach mal ne leere Schleife die nur den DataReader durchspult, und guck wie lange das dauert. Also
// zeitmessung start using (SqlCeDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { } } // zeitmessung ende
Dann weisst du zumindest mal, ob die Zeit in der Datenbank draufgeht (was ich vermute), oder mit deinem C# Code da.
-
Hallo Hustbaer,
ich hab jetzt mal die Zeit gemessen, und ja du hattes recht, allein die leere Schleife is langsam. Was könnte ich nun noch tun? mehr geht woh net!?
grüße
-
NullBockException schrieb:
Was könnte ich nun noch tun? mehr geht woh net!?
Die SQL Abfrage optimieren.
Wenn wir dabei helfen sollen musst du sie aber schon herzeigen...
-
Die SQL abfrage ist schon optimiert
vorher:
SELECT * FROM Archive WHERE BEETWEN DateA AND DataB AND (TagID=1 OR TagID=2 OR TagID=3 OR TagID=4);
nachher:
SELECT * FROM Archive WHERE BEETWEN DateA AND DataB AND TagID IN (1,2,3,4);
Der Witz ist , das er bei der ersten Abfrage "ExecuteQuery" um ein vielfaches langsamer ist als bei der zweiten variante.. die schleife s.o. ist aber immer noch gleich langsam....
-
Falls du mit SQL Server arbeitest, dann sollten beide Abfragen gleichwertig sein, auch was die Performance angeht.
Davon abgesehen brauchst du einen Index auf das Datumsfeld welches du hier unterschlagen hast und/oder auf das TagID Feld. Bzw. auf beide.
Je nachdem welches Kriterium selektiver ist.
Ideal wäre vermutlich:
Falls TagID selektiver als das Datum ist
Index = TagID, Datum
ansonsten
Index = Datum, TagIDUnd wenn die selekivität mal da und mal dort höher ist (je nach Datums-Bereich z.B.), dann einfach beide Indexe anlegen.
-
vieleicht ist es auch besser die ids erst ab zu fragen, das der datumsbereich erst geprueft wird wenn die ids zustimmen
SELECT * FROM Archive WHERE TagID IN (1,2,3,4) AND BEETWEN DateA AND DataB;
-
Das würde mich sehr wundern, wenn MSSQL nicht selber weiss, welche Reihenfolge für ihn besser ist.
Aber im Management Studio sieht man ja immer schön, wielange er wofür brauch.
Ausprobieren kostet ja nix.
-
Mr Evil schrieb:
vieleicht ist es auch besser die ids erst ab zu fragen, das der datumsbereich erst geprueft wird wenn die ids zustimmen
SELECT * FROM Archive WHERE TagID IN (1,2,3,4) AND BEETWEN DateA AND DataB;
Ein guter Anfrageoptimierer sollte sowas aber selbstständig tun. Er wird sicherlich dieselbe Anfragestrategie verwenden egal wie rum man es schreibt.
-
Natürlich ist die Reihenfolge wie man es schreibt egal
SQL Server verwendet den Index, von dem er schätzt dass er selektiver ist. Bzw. wenn es nur einen gibt, dann nimmt er eben den. Und wenn es garkeinen gibt, dann macht es auch genau garkeinen Unterschied, ob zuerst die ID oder zuerst das Datum geprüft wird, da ein Table-Scan sowieso immer langsam ist (ausgenommen relativ kleine Tabellen).
Es würde mich sogar ziemlich wundern, wenn es einen Unterschied zwischen "IN" und "= k1 OR = k2 OR = k2..." gibt - in meinen Tests hat das immer zum gleichen Execution-Plan geführt.
-
Guten Morgen,
ich verwende den SqlCeServer , das is doch ne lite Variante eine SQLServers.. !?
Ne Hustbaer, irgendwie braucht die "ExecutionQuery" ungefähr genausolange wie das iterieren des DataReaders wenn ich ".... AND (TagID=1, TagID=2, TagID=3,TagID=4)" statt ".. AND TagID IN(1,2,3,4)" als ob er das die Datenbank mehrmals durchlaufen würde.
Ich habe Indexe auf Datum und TagID Spalten.
Die Datenbank is ca 45MB groß und hat so 400.000 bis 500.000 Einträge.
-
OK, mit SQL Server CE hab' ich keine Erfahrungen. Auf dem grossen ist es - soweit ich es beobachten konnte - egal.
Wieviele Records liefert die Abfrage denn als Ergebnis?
Und welche Indexe hast du definiert?
-
Hab Indexe auf den Zeitstempel und auf die TagID, wie du erwähnt hast!
Die DAtenbanken liefern so 40.000- 60.000 Datensätze
Ich hab mal einen Test gemacht, und zwar hab ich die "TagID" where Klausel weg gelassen, so das alle Daten in nem best. Zeitbereich zurückgegben werden.
Dann hab ich in der "OleDBReader" Schleife, die TagIDs mal manuel verglichen, hab also bei jeder Iteration mit ner simplen Ling- Query geprüft ob die "TagID" in Bedingung steht.
Nun braucht die ganze Geschichte 30% mehr zeit, als wenn ich die selektion von dem SqlCeEngine erledigen lassse. Was auch logisch ist, das ne Datenbank ja schneller sein sollte.
Wenn ich nun Spasseshalber meine "Linq-Query" weg lasse, also ALLE Datensätze zurückgebe in dem best. Zeitraum, geht es NOCH Länger! Doppelt so lange! das heist die
while(reader.Read()) { ....= reader.GetInt16(); ... }
schleife der OleDbReader ist der Flaschenhals???
-
Wieviel Zeit geht eigentlich fürs DateTime.FromOADate(time) drauf?