tengo una enorme mesa que tengo que leer a través de un cierto orden y calcular algunas estadísticas agregadas. La tabla ya tiene un índice agrupado para el orden correcto, por lo que obtener los registros es bastante rápido. Estoy tratando de usar LINQ to SQL para simplificar el código que necesito escribir. El problema es que no quiero cargar todos los objetos en la memoria, ya que el DataContext parece mantenerlos en todo - sin embargo, tratar de página que se traduce en problemas de rendimiento horrible.Leer enorme mesa con LINQ a SQL: El ejecutarse de memoria vs paginación lenta
Aquí está el desglose. intento original era la siguiente:
var logs =
(from record in dataContext.someTable
where [index is appropriate]
select record);
foreach(linqEntity l in logs)
{
// Do stuff with data from l
}
Esto es bastante rápido, y arroyos a buen ritmo, pero el problema es que el uso de memoria de la aplicación sigue subiendo nunca se detiene. Mi suposición es que las entidades LINQ to SQL se guardan en la memoria y no se eliminan correctamente. Entonces, después de leer Out of memory when creating a lot of objects C#, probé el siguiente enfoque. Este parece ser el paradigma común Skip
/Take
que muchas personas utilizan, con la característica adicional de ahorro de memoria.
Tenga en cuenta que _conn
se crea de antemano, y se crea un contexto temporal de datos para cada consulta, lo que da como resultado que las entidades asociadas sean basura recolectada.
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;
}
}
ahora tengo el comportamiento deseado que el uso de memoria no aumenta en absoluto, ya que estoy streaming a través de los datos. Sin embargo, tengo un problema mucho peor: cada Skip
está causando los datos que se cargan más y más lentamente a medida que la consulta subyacente parece ser la causa realmente el servidor para pasar por todos los datos de todas las páginas anteriores. Al ejecutar la consulta, cada página tarda más y más tiempo en cargarse, y puedo decir que esto se está convirtiendo en una operación cuadrática. Este problema ha aparecido en las siguientes publicaciones:
Me parece que no puede encontrar una manera de hacer esto con LINQ que me permite tener el uso de memoria limitada por la paginación datos, y todavía tienen cada carga de página en tiempo constante. ¿Hay alguna manera de hacer esto correctamente? Mi impresión es que podría haber alguna manera de contar la DataContext olvidar explícitamente sobre el objeto en el primer enfoque anterior, pero no puedo encontrar la manera de hacer eso.
"Tengo una tabla enorme que necesito leer en cierto orden y calcular algunas estadísticas agregadas." - Hágalo en el servidor en TSQL ... ¡Eso es lo que es bueno! –
No, las estadísticas son más complicadas que eso, y no son computables con consultas SQL. Los datos deben repetirse en un orden determinado y las cosas calculadas que son temporalmente correctas, etc. –
"No, las estadísticas son más complicadas que eso, y no son computables con consultas SQL" - ¿en serio? ¿Es posible dar un ejemplo completo? –