2010-12-12 4 views
4

Ich hoffe Laurion Burchall liest diese :-)eine Million kleine Datensätze in Extensible Storage Engine (JetBlue) einlegen - schnell

Ich muss so schnell wie möglich eine Million winziger Datensätze einzufügen.

Im Moment bin ich in einer sehr engen Schleife, wo für jeden Datensatz, ich

a) start a transaction (JetBeginTransaction) 
b) prepare an update (JetPrepareUpdate) 
c) add the row (JetSetColumns) 
d) commit the transaction (JetCommitTransaction) 

Gerade jetzt, während dieses Prozesses habe ich auf einem Prozessor in einer engen Schleife bin. Die Zielmaschine hat mehrere CPUs, große Festplatten und viel freien RAM.

Ich frage mich, wie man bessere Leistung bekommt.

Soweit Transaktionen gehen, habe ich einige Experimente und hatte Probleme, wo Fehler zurückkamen, wenn ich zu viele Daten in einer Transaktion. Ich würde gerne besser verstehen, was dort vor sich geht - habe ich einen Fehler, oder ist die Größe einer Transaktion begrenzt? Kann ich die Obergrenze vergrößern? Ich untersuche das nur, weil ich vermute, dass eine Transaktion ESE die Möglichkeit gibt, mehr Zwischenspeicher im RAM zu machen, was das Löschen von Festplatten minimiert? - Das ist nur eine Vermutung?

Im Allgemeinen, wie benutze ich mehrere Prozessoren/viel RAM/und nette Festplatten? öffne ich die Datenbank zweimal und gehe von dort? Ich bin mir nicht sicher, was in Bezug auf Thread-Sicherheit und Transaktionen passiert. Wenn ich zwei Handles zur Datenbank habe, jeder in einer Transaktion, wird ein Schreiben auf einen Handle unmittelbar vor dem Commit für den zweiten verfügbar sein, oder muss ich zuerst Commit machen?

sind alle Tipps

here are the constraints  

a) I've got a million records that need to be written into the DB as fast as possible 
b) to fully generate the record for insertion there are two searches that need to occur within the same table (seeking keys) 
c) This is a rebuild/regeneration of the DB - it either worked, or it didnt. 
    If it didnt there is no going back, a fresh rebuild/regeneration is 
    needed. I cannot restart mid process and without all the data none of 
    the data is valuable. READ: having one big transaction is fine if it 
    improves perf. I'd like ESE to cache, in ram, if that helps perf. 

Dank geschätzt!

Antwort

5

Für Single-Thread-Leistung ist das wichtigste zu betrachten Ihr Transaktionsmodell.

Wenn Sie versucht haben, mehr Daten in eine Transaktion zu schreiben, und es fehlgeschlagen ist, haben Sie wahrscheinlich einen JET_errOutOfVersionStore erhalten. Esent muss Informationen für alle Operationen rückverfolgen, die in einer Transaktion ausgeführt werden (um Rollback zu ermöglichen), und diese Informationen werden im Versionsspeicher gespeichert. Die Standardgröße des Versionsspeichers ist ziemlich klein. Sie können es mit dem Systemparameter JET_paramMaxVerPages erhöhen. Ein Wert von 1024 (64 MB Versionsspeicher) ermöglicht ziemlich große Transaktionen. Ich schlage vor, 100-1000 Einfügungen pro Transaktion zu machen.

Wenn Sie JetCommitTransaction aufrufen, löscht Esent das Protokoll auf die Festplatte und generiert eine synchrone E/A. Um dies zu vermeiden, übergeben Sie JET_bitCommitLazyFlush an JetCommitTransaction. Ihre Transaktionen werden im Falle eines Absturzes zwar immer noch atomar, aber nicht dauerhaft sein (bei normalem Beenden werden die Dinge in Ordnung sein). Es sieht so aus, als müsste das für Ihre Verwendung gefunden werden.

Wenn Sie Datensätze in aufsteigender Reihenfolge einfügen, können Sie möglicherweise mit einer Singlethread-Anwendung davonkommen. Wenn Sie Ihre Implementierung ändern können, um sequenzielle Einfügungen zu machen, sollten Sie - sie sind viel schneller. Für zufällige Inserts können mehrere Threads nützlich sein. Um mehrere Threads zu verwenden, müssen Sie nur neue Sitzungen (JetBeginSession) erstellen und sie die Datenbank (JetOpenDatabase) öffnen lassen. Esent verwendet Snapshot isloation(), so dass Änderungen, die von anderen Sitzungen vorgenommen wurden, die nach Beginn der Transaktion nicht festgeschrieben oder festgeschrieben wurden, nicht angezeigt werden. Dies ist anders als Read-Committed, wo Sie Änderungen sehen können, sobald eine andere Sitzung festgeschrieben wurde. Sie müssen möglicherweise darüber nachdenken, wie Sie die Arbeit aufteilen, um damit umzugehen.

+0

vielen dank! – stuck

+0

Hier ist ein Link zu einem Dokument Laurion auf MSDN http://blogs.msdn.com/b/laurionb/archive/2008/11/07/some-basic-esent-performance-measurements.aspx – stuck

+0

Ich bin nicht die Perfusion bekommen, die ich gerne sehen würde. Ich kann ~ 10.000 sehr kleine Aufzeichnungen in ungefähr 4.3sec auf einer netten Maschine (i7 mit 7200 SATA-Scheibe) hinzufügen. Das Problem tritt nur auf, wenn der Datenbank eine einzelne, eindeutige Zeichenfolge ungleich null hinzugefügt wird. Ich sehe niedrige CPU-Auslastung und viele kleine Schreibvorgänge beim Überwachen mit Procmon. Das erscheint mir angesichts der geringen Größe der Aufzeichnungen? Ich rufe JetCommitTransaction (JET_bitCommitLazyFlush). Alles vorausgesetzt (Lazy Flush + großer maxVerPage-Wert + niedrige CPU-Last + kleine IOs, gemessen in procmon). Etwas das ich tun kann? Angenommen, die Bewegung der Platte ist wahrscheinlich? – stuck

1

Stellen Sie sicher, dass Sie "in Reihenfolge" einfügen. Was ist der geclusterte (primäre) Schlüssel? Ist es eine künstliche Auto-Inc? Wenn ja, dann fügen Sie in Reihenfolge ein.Wie viele Sekundärindizes haben Sie? Idealerweise würden Sie keine haben, so dass alle Einsätze, z.B. das gruppierte Insert allein würde in der Indexreihenfolge sein. Wenn Sie in die Indexreihenfolge einfügen, hängt das JetUpdate nur an das Ende eines Indexes an. Das ist viel schneller als Einfügen in die Mitte eines Indexes. Hoffe, das hilft, Ian.

Verwandte Themen