2010-11-25 8 views
1

私は約180,000レコードのデータベースを持っています。私はこれらのレコードのそれぞれにpdfファイルを添付しようとしています。各pdfのサイズは約250kbです。しかし、約1分後に私のプログラムは約1 GBのメモリを使い始め、私はそれをやめなければなりません。私はそれをやってみましたので、各linqオブジェクトへの参照は一度更新されても削除されますが、それは役に立たないようです。参照をクリアするにはどうすればよいですか?あなたの助けlinqサブチェンジのメモリが不足しています

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 

答えて

4

ため

おかげで私はあなたが一度にアイテムの特定の数を処理するために(ToListの呼び出しの前Takeを使用して、バッチでこれを行うことをお勧めします。 10を読んで、PDFContentに設定し、すべてに設定してSubmitChangesに電話してから、もう一度やり直してください。 (私はその時点で新しいDataContextから始めなければならないかどうかはわかりませんが、そうするのが一番きれいかもしれません)。

ファイルの内容を読み取るコードは、少なくとも2つの方法がありますが、最初はFile.ReadAllBytesを使用する方が簡単です。

また、縮小徐々にリストを処理するあなたの方法が本当に非効率的である - 18万レコードをフェッチした後、あなたはその後、など179998件のレコードを別の、その後、179999件のレコードを

+0

私はこの方法をとっていましたが、しばしばプログラムを遅くする初期クエリを実行していました。私はそれを行うより適切な方法があることを望んでいた。 – Leon

+0

非常に助けていただきありがとうございますbtw – Leon

+1

@レーオン:わずか18万レコードで、検索は驚異的に速くなるはずです。そうでない場合は、索引付け(特にPDFFolder'を参照)を調べることをお勧めします。たぶん10レコードから100レコードに上がります...基本的には適切なバランスを見つけようとします。 –

0

を新しいリストを構築しているのDataContextを持っていますObjectTrackingEnabledをtrue(デフォルト値)に設定していますか?そうであれば、ガベージコレクタがそれを収集できないように、それが触れる本質的にすべてのデータの記録を保持しようとします。

もしそうなら、定期的にDataContextを配置して新しいものを作成するか、オブジェクトトラッキングをオフにすることで状況を修正できるはずです。

+1

待ってはいけません。オブジェクトの追跡をオフにすると、切断されません。なぜなら、SubmitChanges()を呼び出すと例外が発生するからです。 Jon Skeet氏のアイデアに沿ってデータを処理し、DataContextを破棄し、各部分の後に新しいデータコンテキストを作成する必要があると思います。 –

0

OK。最小量のメモリを使用するには、ブロック内のdatacontextを更新する必要があります。私は以下にサンプルコードを書いた。私はそれを入力するメモ帳を使用していますので、sytaxエラーがある可能性があります。

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 

をさらにあなたは匿名型としてallitemsから配列にレコードID年代を取得し、そのPDFフィールドの上DelayLoading設定できる速度を最適化するには。

+0

また、.Where(RowID> lastOffsetおよびRowID

関連する問題