2010-11-25 5 views
1

Ich habe eine Datenbank mit etwa 180.000 Datensätze. Ich versuche, eine PDF-Datei an jeden dieser Datensätze anzuhängen. Jedes pdf ist ungefähr 250 kb groß. Nach ungefähr einer Minute beginnt mein Programm jedoch mit etwa einem GB Speicher und ich muss es stoppen. Ich habe versucht, es so zu tun, dass der Verweis auf jedes linq-Objekt entfernt wird, sobald es aktualisiert wird, aber das scheint nicht zu helfen. Wie kann ich die Referenz klarstellen?linq submitchanges hat keinen Speicher mehr

Danke für Ihre Hilfe

Private Sub uploadPDFs(ByVal args() As String) 
    Dim indexFiles = (From indexFile In dataContext.IndexFiles 
        Where indexFile.PDFContent = Nothing 
        Order By indexFile.PDFFolder).ToList 
    Dim currentDirectory As IO.DirectoryInfo 
    Dim currentFile As IO.FileInfo 
    Dim tempIndexFile As IndexFile 

    While indexFiles.Count > 0 
     tempIndexFile = indexFiles(0) 
     indexFiles = indexFiles.Skip(1).ToList 
     currentDirectory = 'I set the directory that I need 
     currentFile = 'I get the file that I need 
     writePDF(currentDirectory, currentFile, tempIndexFile) 
    End While 
End Sub 

Private Sub writePDF(ByVal directory As IO.DirectoryInfo, ByVal file As IO.FileInfo, ByVal indexFile As IndexFile) 
    Dim bytes() As Byte 
    bytes = getFileStream(file) 
    indexFile.PDFContent = bytes 
    dataContext.SubmitChanges() 
    counter += 1 
    If counter Mod 10 = 0 Then Console.WriteLine("  saved file " & file.Name & " at " & directory.Name) 
End Sub 


Private Function getFileStream(ByVal fileInfo As IO.FileInfo) As Byte() 
    Dim fileStream = fileInfo.OpenRead() 
    Dim bytesLength As Long = fileStream.Length 
    Dim bytes(bytesLength) As Byte 

    fileStream.Read(bytes, 0, bytesLength) 
    fileStream.Close() 

    Return bytes 
End Function 

Antwort

4

Ich schlage vor, Sie dies in Chargen durchführen, mit Take (vor den Anruf an ToList) zu einem Zeitpunkt eine bestimmte Anzahl von Elementen zu verarbeiten. Lesen Sie (sagen Sie) 10, setzen Sie die PDFContent auf alle von ihnen, rufen Sie SubmitChanges, und starten Sie erneut. (Ich bin mir nicht sicher, ob Sie zu diesem Zeitpunkt mit einem neuen DataContext beginnen sollten, aber es könnte am saubersten sein.)

Nebenbei ist Ihr Code zum Lesen des Inhalts einer Datei in gebrochen zumindest ein paar Wege - aber es wäre einfacher, nur File.ReadAllBytes in erster Linie zu verwenden.

Auch Ihr Weg, um die Liste nach und nach schrumpfen Handhabung ist wirklich ineffizient - nach 180.000 Datensätze zu holen, sind Sie dann eine neue Liste mit 179.999 Datensätzen aufzubauen, dann die andere mit 179.998 Datensätzen usw.

+0

Ich dachte daran, es auf diese Weise zu machen, aber die erste Abfrage auszuführen, die mein Programm oft verlangsamen würde. Ich hatte gehofft, es gäbe einen besseren Weg. – Leon

+0

vielen Dank für Ihre Hilfe btw – Leon

+1

@Leon: Mit nur 180.000 Aufzeichnungen sollte eine Suche blitzschnell sein. Wenn dies nicht der Fall ist, sollten Sie sich Ihre Indexierung ansehen (insbesondere auf "PDFFolder"). Vielleicht von 10 auf 100 aufsteigen ... versuche im Grunde, ein angemessenes Gleichgewicht zu finden. –

0

Hat der Datacontext haben ObjectTrackingEnabled auf true gesetzt (der Standardwert)? Wenn dies der Fall ist, wird es versuchen, im Wesentlichen alle Daten, die es berührt, aufzuzeichnen, wodurch verhindert wird, dass der Müllsammler etwas davon erfassen kann.

Wenn dies der Fall ist, sollten Sie in der Lage sein, die Situation zu beheben, indem Sie regelmäßig den DataContext entsorgen und einen neuen erstellen oder die Objektverfolgung deaktivieren.

+1

Keine Wartezeit, wenn das Objekt-Tracking ausgeschaltet wird, wird es nicht abgeschnitten, denn dann erhalten Sie eine Ausnahme, wenn Sie SubmitChanges() aufrufen. Ich denke, Sie müssen Jon Skeets Idee folgen, die Daten in Teilen zu bearbeiten, den DataContext zu entsorgen und nach jedem Stück einen neuen zu erstellen. –

0

OK. Um die kleinste Menge an Speicher zu verwenden, müssen wir den Datenkontext in Blöcken aktualisieren. Ich habe unten einen Beispielcode eingegeben. Könnte sytax Fehler haben, da ich Notizblock bin mit darin eingeben.

Dim DB as YourDataContext = new YourDataContext 
    Dim BlockSize as integer = 25 
    Dim AllItems = DB.Items.Where(function(i) i.PDFfile.HasValue=False) 

    Dim count = 0 
    Dim tmpDB as YourDataContext = new YourDataContext 


While (count < AllITems.Count) 

    Dim _item = tmpDB.Items.Single(function(i) i.recordID=AllItems.Item(count).recordID) 
    _item.PDF = GetPDF() 

    Count +=1 

    if count mod BlockSize = 0 or count = AllItems.Count then 
     tmpDB.SubmitChanges() 
     tmpDB = new YourDataContext 
      GC.Collect() 
    end if 

End While 

, um die Geschwindigkeit zu optimieren Sie die recordID die in ein Array von AllItems als anonymer Typ bekommen können, und stellen Sie für das PDF-Feld DelayLoading auf .

+0

Sie können auch .Where (RowID> lastOffset und RowID