I have one table with 500,000 records, and within my application I make some filters and the query returns me 410,000, now dont get me wrong, I do not display that data on the screen, its a financial application where every day that table needs to processed and make some calculations in memory and write some totals back to other tables.
I dont want to paste my entire model as it wouldnt fit the purpose of this question, the questions is how can I optimize EF to make the query faster, I tried using SQL Profile and to return those 410,000 it takes 11 minutes.
private List<MasterVenta> FilterMasterVentas(RuleEditor filter, ComisionPorProveedor comisionPorProveedor)
{
Periodo periodo = comisionPorProveedor.Periodo;
var strReferences = new StringBuilder();
var Modelo_PuntoVentaProveedor = nameof(MasterVenta.PuntoVentaProveedor);
var Modelo_PuntoVentaProveedor_proveedor = Modelo_PuntoVentaProveedor + "." + nameof(PuntosVentaProveedor.Proveedor);
var Modelo_PuntoVentaProveedor_Liquidaciones = Modelo_PuntoVentaProveedor + "." + nameof(PuntosVentaProveedor.Liquidaciones);
var Modelo_PuntoVentaProveedor_Proveedor_TipoDeCanal = Modelo_PuntoVentaProveedor_proveedor + "." + nameof(Proveedor.TipoDeCanal);
//var Modelo_PuntoVentaProveedor_Proveedor_Productos = Modelo_PuntoVentaProveedor_proveedor + "." + nameof(Proveedor.Productos);
var Modelo_PuntoVentaProveedor_Proveedor_ContactosProveedor = Modelo_PuntoVentaProveedor_proveedor + "." + nameof(Proveedor.ContactosProveedor);
var Modelo_PuntoVentaProveedor_Proveedor_Contrato = Modelo_PuntoVentaProveedor_proveedor + "." + nameof(Proveedor.Contrato);
var Modelo_PuntoVentaProveedor_Proveedor_ComisionesPorProveedor = Modelo_PuntoVentaProveedor_proveedor + "." + nameof(Proveedor.ComisionesPorProveedor);
strReferences.Append(Modelo_PuntoVentaProveedor);
strReferences.Append("," + Modelo_PuntoVentaProveedor_Liquidaciones);
strReferences.Append("," + Modelo_PuntoVentaProveedor_Proveedor_TipoDeCanal);
//strReferences.Append("," + Modelo_PuntoVentaProveedor_Proveedor_Productos);
strReferences.Append("," + Modelo_PuntoVentaProveedor_Proveedor_ContactosProveedor);
strReferences.Append("," + Modelo_PuntoVentaProveedor_Proveedor_Contrato);
strReferences.Append("," + Modelo_PuntoVentaProveedor_Proveedor_ComisionesPorProveedor);
//el master de ventas debe filtrase por el periodo, PuntoVenta, TipoDeCanal,Producto
List<int> puntosVenta = comisionPorProveedor.Proveedor.PuntosVentaProveedor.Select(p => p.PuntoVentaProveedorId).ToList();//tipo de canal de proveedor de acuerdo a la tabla comisionPorProveedor
if (filter.Rule.IsEmpty()) return null;
if (!filter.Rule.IsValid()) return null;
var q = (from c in this.unitOfWork.MasterVentaRepository.Get(null, o => o.OrderBy(x => x.MasterVentaID), strReferences.ToString()).Filter<MasterVenta>(filter.Rule.GetRuleXml())
where c.FechaVenta != null &&
(
(DateTime.Compare(c.FechaVenta.Value, periodo.FechaFinal) <= 0)
&& (DateTime.Compare(c.FechaVenta.Value, periodo.FechaInicial) >= 0)
)
&&
(c.PuntoVentaProveedor != null &&
(
(puntosVenta.Any(pv => c.PuntoVentaProveedor != null && pv == c.PuntoVentaProveedor.PuntoVentaProveedorId)
|| c.PuntoVentaProveedor.PuntoDeVentaHistorials.Any(p => c.PuntoVentaProveedor != null && c.FechaVenta >= p.FechaInicio && c.FechaVenta <= p.FechaFin))
))
select c);
var result = q.ToList();
return result;
}
The line that takes 11 minutes is this one
var q = (from c in this.unitOfWork.MasterVentaRepository.Get(null, o => o.OrderBy(x => x.MasterVentaID), strReferences.ToString()).Filter<MasterVenta>(filter.Rule.GetRuleXml())
where c.FechaVenta != null &&
(
(DateTime.Compare(c.FechaVenta.Value, periodo.FechaFinal) <= 0)
&& (DateTime.Compare(c.FechaVenta.Value, periodo.FechaInicial) >= 0)
)
&&
(c.PuntoVentaProveedor != null &&
(
(puntosVenta.Any(pv => c.PuntoVentaProveedor != null && pv == c.PuntoVentaProveedor.PuntoVentaProveedorId)
|| c.PuntoVentaProveedor.PuntoDeVentaHistorials.Any(p => c.PuntoVentaProveedor != null && c.FechaVenta >= p.FechaInicio && c.FechaVenta <= p.FechaFin))
))
the .get method is like this one:
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet.AsNoTracking();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}