SubmitChanges LINQ esaurisce la memoria
-
28-09-2019 - |
Domanda
Ho un database con circa 180.000 record. Sto cercando di allegare un file pdf a ciascuno di questi record. Ogni pdf è di circa 250 kb di dimensione. Tuttavia, dopo circa un minuto il mio programma inizia a prendere su di un GB di memoria e devo fermarlo. Ho provato a fare in modo che il riferimento a ciascun oggetto LINQ viene rimossa una volta che è aggiornato, ma che non sembra aiuto. Come posso mettere in chiaro il riferimento?
Grazie per il vostro aiuto
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
Soluzione
Vi suggerisco di eseguire questo in lotti, utilizzando Take
(< em> prima la chiamata a ToList
) di elaborare un particolare numero di elementi alla volta. Leggi (diciamo) 10, impostare il PDFContent
su tutti di loro, chiamata SubmitChanges
, e poi ricominciare. (Non sono sicuro se due piedi si dovrebbe iniziare con una nuova DataContext
a quel punto, ma potrebbe essere più pulito di farlo.)
Per inciso, il codice per leggere il contenuto di un file è suddiviso in almeno un paio di modi - ma sarebbe più semplice usare File.ReadAllBytes
in primo luogo.
Inoltre, il tuo modo di gestire la lista gradualmente restringimento è davvero inefficiente - dopo il recupero 180.000 record, si sta quindi costruendo un nuovo elenco con 179,999 record, poi un altro con 179,998 record etc
.Altri suggerimenti
fa il DataContext hanno ObjectTrackingEnabled impostata su true (il valore predefinito)? Se è così, allora sarà cercare di mantenere un registro di essenzialmente tutti i dati che tocca, impedendo così il garbage collector di essere in grado di raccogliere qualsiasi di esso.
Se è così, si dovrebbe essere in grado di risolvere la situazione periodicamente smaltire il DataContext e la creazione di uno nuovo, o girando oggetto di monitoraggio off.
OK. Per utilizzare la più piccola quantità di memoria che dobbiamo aggiornare il DataContext in blocchi. Ho messo un codice di esempio. Potrebbe avere errori sytax dal momento che sto utilizzando il Blocco note di digitare in.
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
Per ottimizzare ulteriormente la velocità si può ottenere il recordID di in un array da AllItems come un tipo anonimo, e DelayLoading impostato su quel campo per PDF.