Lesen Sie eine große Tabelle mit LINQ to SQL: Nicht genügend Arbeitsspeicher im Vergleich zu langsamem Paging

Ich habe eine riesige Tabelle, die ich in einer bestimmten Reihenfolge durchlesen und einige aggregierte Statistiken berechnen muss. Die Tabelle enthält bereits einen Clustered-Index für die richtige Reihenfolge, sodass das Abrufen der Datensätze selbst ziemlich schnell ist. Ich versuche, LINQ to SQL zu verwenden, um den Code zu vereinfachen, den ich schreiben muss. Das Problem ist, dass ich nicht alle Objekte in den Speicher laden möchte, da der DataContext sie offenbar in der Nähe hält - und der Versuch, sie zu paginieren, zu schrecklichen Leistungsproblemen führt.

Hier ist die Aufschlüsselung. Ursprünglicher Versuch war dieser:

var logs = 
    (from record in dataContext.someTable 
     where [index is appropriate]
     select record);

foreach( linqEntity l in logs )
{
    // Do stuff with data from l
}

Dies ist ziemlich schnell und strömt mit einer guten Rate, aber das Problem ist, dass die Speichernutzung der Anwendung immer weiter zunimmt. Ich vermute, dass die LINQ to SQL-Entitäten im Arbeitsspeicher gespeichert und nicht ordnungsgemäß entsorgt werden. Also nach dem LesenNicht genügend Speicher beim Erstellen vieler Objekte C # Ich habe den folgenden Ansatz ausprobiert. Dies scheint die Regel zu seinSkip/Take Ein Paradigma, das viele Menschen verwenden, mit der zusätzlichen Funktion, Speicherplatz zu sparen.

Beachten Sie, dass_conn wird vorab erstellt, und für jede Abfrage wird ein temporärer Datenkontext erstellt, der dazu führt, dass die zugeordneten Entitäten müllsammelbar sind.

int skipAmount = 0;
bool finished = false;

while (!finished)
{
    // Trick to allow for automatic garbage collection while iterating through the DB
    using (var tempDataContext = new MyDataContext(_conn) {CommandTimeout = 600})
    {               
        var query =
            (from record in tempDataContext.someTable
             where [index is appropriate]
             select record);

        List<workerLog> logs = query.Skip(skipAmount).Take(BatchSize).ToList();
        if (logs.Count == 0)
        {
            finished = true;
            continue;
        }

        foreach( linqEntity l in logs )
        {
            // Do stuff with data from l
        }

        skipAmount += logs.Count;
    }
}

Jetzt habe ich das gewünschte Verhalten, dass die Speichernutzung beim Streaming der Daten überhaupt nicht zunimmt. Dennoch habe ich ein weitaus schlimmeres Problem: jedesSkip führt dazu, dass die Daten immer langsamer geladen werden, da die zugrunde liegende Abfrage dazu zu führen scheint, dass der Server alle Daten für alle vorherigen Seiten durchläuft. Während die Abfrage ausgeführt wird, dauert das Laden jeder Seite immer länger, und ich kann feststellen, dass dies zu einer quadratischen Operation wird. Dieses Problem ist in den folgenden Beiträgen aufgetreten:

LINQ Skip () ProblemLINQ2SQL Aufträge auswählen und überspringen / übernehmen

Ich kann mit LINQ anscheinend keinen Weg finden, dies zu tun, der es mir ermöglicht, durch Paging-Daten eine begrenzte Speichernutzung zu erzielen und dennoch jede Seite in konstanter Zeit zu laden. Gibt es eine Möglichkeit, dies richtig zu tun?Ich vermute, dass es eine Möglichkeit gibt, den DataContext anzuweisen, das Objekt im ersten Ansatz oben explizit zu vergessen, aber ich kann nicht herausfinden, wie das geht.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage