Hallo Forum,
ich weiß, das Auslesen von Textdateien, auch das von sehr großen, sollte eigentlich trivial sein und schon gar nicht ins Forum für Fortgeschrittene gehören, aber ich kaue nun schon seit zwei Tagen an einem Problem (komme trotz Google und suchen in einigen Foren nicht weiter), das mich mehr und mehr von dieser Ansicht befreit:
Ich habe mir ein kleines Downloadtool geschrieben, das mir den Dump der MusicBrainz-DB von deren FTP-Server herunterladen, mittels 7z.exe entpacken und in eine SQLite-DB überführen soll. Das Herunterladen und Entpacken funktionieren gut, aber beim Einlesen in die SQLite-DB klemmts heftig.
Die entpackten Tabellen sind unterschiedlich groß (10KB bis 600MB) und liegen als vbTab separierte Textdateien vor, mit einem vbLf am Zeilenende. Die Zeilen haben eine unterschiedliche Anzahl an Elementen (3 bis 17), von denen ich mir beim Einlesen mittels FileStream und StreamReader die benötigten herauspicke. Um eine Fortschrittsanzeige zu realisieren, läuft das das Ganze asynchron im BackGroundWorker:
Private Sub BWr_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
...
If File.Exists(TblPath & "\" & TblName) Then
Try
SQLconn.Open()
SQLtrans = SQLcomm.Connection.BeginTransaction()
'tblAlbum: AlbumID (primKey), ArtistID, AlbumName, AlbumGID,
' AlbumLanguage
SQLcomm.Parameters.Add("@id", DbType.Int32)
SQLcomm.Parameters.Add("@artist", DbType.Int32)
SQLcomm.Parameters.Add("@name", DbType.String)
SQLcomm.Parameters.Add("@gid", DbType.String)
SQLcomm.Parameters.Add("@language", DbType.Int32)
SQLcomm.CommandText = "INSERT INTO " & TblName & _
" VALUES(@id, @artist, @name, @gid, @language)"
FS = New FileStream(TblPath & "\" & TblName, FileMode.Open, _
FileAccess.Read)
SR = New StreamReader(FS)
BytesTotal = SR.BaseStream.Length
Do While SR.Peek() >= 0
TxtLineArr = Split(SR.ReadLine(), vbTab)
If BWr.CancellationPending = True Then
e.Cancel = True
SR.Close()
SQLtrans.Rollback()
SQLconn.Close()
Exit Sub
End If
SQLcomm.Parameters("@id").Value = CInt(TxtLineArr(0))
SQLcomm.Parameters("@artist").Value = CInt(TxtLineArr(1))
SQLcomm.Parameters("@name").Value = Replace(TxtLineArr(2), _
"''", "'")
SQLcomm.Parameters("@gid").Value = TxtLineArr(3)
If TxtLineArr(7) = "\N" Then
SQLcomm.Parameters("@language").Value = DBNull.Value
Else
SQLcomm.Parameters("@language").Value = CInt(TxtLineArr( _
7))
End If
SQLcomm.ExecuteNonQuery()
BytesRead = FS.Position
BWr.ReportProgress(CInt(BytesRead / BytesTotal * 100))
Loop
SR.Close()
SQLtrans.Commit()
SQLconn.Close()
Catch ex As Exception
e.Cancel = True
MsgBox("Fehler beim Einlesen der Tabelle " & TblName & " :" & _
Chr(13) & ex.Message)
End Try
Else
e.Cancel = True
MsgBox("Tabelle" & Chr(13) & TblPath & "\" & TblName & Chr(13) & _
"nicht vorhanden")
End If Zum Einlesen der Textdateien habe ich den Laptop (AcerTravelMate5220, DualCore AMD 2x1,9GHz, 2GB RAM, XP, Visual Express 2005) jeweils neu gestartet, eine neue SQLite-DB mit nur der Zieltabelle angelegt und folgendes gemessen:
Erste Textdatei 48,5MB, 12 Elemente je Zeile, davon 2 übernommen: Dauer bis beendet = 29,7sec (toller Wert, nur ab dem 42. MB wird das Einlesen etwas langsamer).
Obiges Beispiel: Textdatei 75,6MB, 12 Elemente je Zeile: Dauer bis beendet = 387,9sec (ab dem 37. MB wird das Einlesen zunehmend langsamer, er gönnt sich dann ca. 3sec für 100kb - gähn!!).
Ganz schlimm: Dritte Textdatei 644,1MB, 7 Elemente je Zeile, davon 4 übernommen: Dauer bis beendet: ca. 40min! (hier wird schon ab den 15. MB wird das Einlesen zunehmend langsamer, auch hier gönnt er sich dann ca. 3sec für 100kb)
Zeitgleich mit dem langsamwerden bricht die CPU-Auslastung von ca. 92% auf 16 bis 19% zusammen. Der Sytemcache läuft kontinuierlich voll.
Weiß jemand Abhilfe? Wie man das Einlesen gleichmäßig schnell hinbekommt? Evtl. auch ressourcenschonender?
Dank schon im voraus
PS: Ich habe, um ressourcenschonender zu sein, schon den ODBCDatareader eingesetzt, nur der konnte keine Sonderzeichen und brach mitten im Einlesen unvermittelt ab.
Beitrag wurde zuletzt am 16.05.09 um 15:40:17 editiert. |