Mam ogromny stół, który muszę przeczytać w określonej kolejności i obliczyć niektóre zbiorcze statystyki. Tabela ma już indeks klastrowy dla prawidłowej kolejności, więc sama rejestracja jest dość szybka. Próbuję użyć LINQ do SQL, aby uprościć kod, który muszę napisać. Problem polega na tym, że nie chcę ładować wszystkich obiektów do pamięci, ponieważ wydaje się, że DataContext utrzymuje je w pobliżu - ale próba ich przesłania skutkuje okropnymi problemami z wydajnością.Przeczytaj ogromną tabelę z LINQ do SQL: Wyczerpanie pamięci vs powolne stronicowanie
Oto podział. Oryginalna próba była to:
var logs =
(from record in dataContext.someTable
where [index is appropriate]
select record);
foreach(linqEntity l in logs)
{
// Do stuff with data from l
}
Jest to dość szybko, i strumienie w dobrym tempie, ale problemem jest to, że użycie pamięci aplikacji ciągle dzieje się nigdy nie zatrzyma. Domyślam się, że obiekty LINQ do SQL są przechowywane w pamięci i nie są prawidłowo usuwane. Po przeczytaniu Out of memory when creating a lot of objects C# spróbowałem następującego podejścia. Wydaje się, że jest to powszechny paradygmat używany przez wiele osób, z dodatkową funkcją oszczędzania pamięci.
Należy pamiętać, że wcześniej utworzono _conn
, a dla każdego zapytania tworzony jest kontekst danych tymczasowych, co powoduje, że skojarzone elementy są usuwane ze śmieci.
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;
}
}
Teraz mam pożądane zachowanie, że użycie pamięci nie zwiększa się w ogóle, ponieważ przesyłam dane strumieniowo. Jednak mam o wiele gorszy problem: każdy proces Skip
powoduje, że dane ładują się coraz wolniej, ponieważ podstawowe zapytanie wydaje się w rzeczywistości spowodować, że serwer przejdzie przez wszystkie dane dla wszystkich poprzednich stron. Podczas uruchamiania zapytania każda strona ładuje się dłużej i dłużej, i mogę powiedzieć, że zamienia się ona w operację kwadratową. Problem ten pojawił się w następujących stanowisk:
I nie wydają się znaleźć sposób, aby to zrobić z LINQ, która pozwala mi mieć ograniczone zastosowanie pamięci przez stronicowania danych, a mimo to każda strona ładuje się w stałym czasie. Czy istnieje sposób, aby to zrobić właściwie? Moje przeczucie polega na tym, że może istnieć jakiś sposób, aby powiedzieć DataContext, aby wyraźnie zapomniał o obiekcie w pierwszym podejściu powyżej, ale nie mogę się dowiedzieć, jak to zrobić.
"Mam ogromny stół, który muszę przeczytać w określonej kolejności i obliczyć niektóre statystyki zbiorcze." - Zrób to na serwerze w TSQL .... To jest to, co jest dobre w! –
Nie, statystyki są bardziej skomplikowane i nie można ich obliczać za pomocą zapytań SQL. Dane muszą być iterowane za pomocą w określonej kolejności i obliczone rzeczy, które są tymczasowo poprawne, itp. –
"Nie, statystyki są bardziej skomplikowane i nie są obliczalne z zapytaniami SQL" - naprawdę? Czy da się podać pełny przykład? –