Obtención de la lista de goles del equipo diario -- # campo con performance campo con linq campo con entity-framework campo con asp.net-mvc camp codereview Relacionados El problema

Getting list of daily team goals


5
vote

problema

Español

El código anterior que tuve antes fue atrozmente lento, pero después de algunos consejos e investigaciones, pude tomar un tiempo de ejecución de 2 a 5 minutos hasta unos 5-30 segundos. Eso es aceptable, pero aún está buscando que se ejecute lo más rápido posible.

Todavía lo estoy limpiando, como si no deberían haber dos llamadas de entidades PP separadas.

  public static List<DailyTeamGoal> GetListDailyTeamGoals(int teamId) {     string teamGoal = "";     List<ProPit_User> lstProPit_User = new List<ProPit_User>();     using (PPEntities db = new PPEntities())     {         Team team = db.Teams.Where(x => x.teamID == teamId).FirstOrDefault();          if (team != null)         {             teamGoal = Convert.ToString(team.goal);         }          lstProPit_User = db.ProPit_User.Where(x => x.teamID == teamId).ToList();     }      List<DailyTeamGoal> lstDailyTeamGoal = new List<DailyTeamGoal>();     using (TEntities db = new TEntities())     using (PPEntities ppdb = new PPEntities())     {         //have to get every day of the month         DateTime dt = DateTime.Now;         int days = DateTime.DaysInMonth(dt.Year, dt.Month);         decimal orderTotal = 0m;         for (int day = 1; day <= DateTime.Now.Day; day++)         {             DailyTeamGoal dtg = new DailyTeamGoal();             dtg.Date = day.ToString(); //dt.Month + "/" + day; + "/" + dt.Year;             dtg.TeamGoal = teamGoal;             //decimal orderTotalRep = 0m;              DateTime dtStartDate = Convert.ToDateTime(dt.Month + "/" + day + "/" + dt.Year);             DateTime dtEndDate = dtStartDate.AddDays(1);              var ordersQuery = db.Orders.Where(o => o.DateCompleted >= dtStartDate                                                 && o.DateCompleted <= dtEndDate                                                 && (o.Status == 1 || o.Status == 2)                                                 && o.Kiosk != 0).ToList();              var lstSalesRepIDs = ppdb.ProPit_User                 .Where(x => x.teamID == teamId).Select(v => v.SalesRepID).ToList();              var total = (from o in ordersQuery                             where lstSalesRepIDs.Contains(o.SalesRepID)                             select o.OrderTotal).Sum();              orderTotal += total;             dtg.DailyTotal = orderTotal;              lstDailyTeamGoal.Add(dtg);         }     }      return lstDailyTeamGoal; }   
Original en ingles

The old code I had before was atrociously slow but after some advice and research I was able to take a 2-5 minutes run time down to about 5-30 seconds. That is acceptable, but still looking to have it run as quickly as possible.

I'm still cleaning it up, like there shouldn't be two seperate PP entities calls.

public static List<DailyTeamGoal> GetListDailyTeamGoals(int teamId) {     string teamGoal = "";     List<ProPit_User> lstProPit_User = new List<ProPit_User>();     using (PPEntities db = new PPEntities())     {         Team team = db.Teams.Where(x => x.teamID == teamId).FirstOrDefault();          if (team != null)         {             teamGoal = Convert.ToString(team.goal);         }          lstProPit_User = db.ProPit_User.Where(x => x.teamID == teamId).ToList();     }      List<DailyTeamGoal> lstDailyTeamGoal = new List<DailyTeamGoal>();     using (TEntities db = new TEntities())     using (PPEntities ppdb = new PPEntities())     {         //have to get every day of the month         DateTime dt = DateTime.Now;         int days = DateTime.DaysInMonth(dt.Year, dt.Month);         decimal orderTotal = 0m;         for (int day = 1; day <= DateTime.Now.Day; day++)         {             DailyTeamGoal dtg = new DailyTeamGoal();             dtg.Date = day.ToString(); //dt.Month + "/" + day; + "/" + dt.Year;             dtg.TeamGoal = teamGoal;             //decimal orderTotalRep = 0m;              DateTime dtStartDate = Convert.ToDateTime(dt.Month + "/" + day + "/" + dt.Year);             DateTime dtEndDate = dtStartDate.AddDays(1);              var ordersQuery = db.Orders.Where(o => o.DateCompleted >= dtStartDate                                                 && o.DateCompleted <= dtEndDate                                                 && (o.Status == 1 || o.Status == 2)                                                 && o.Kiosk != 0).ToList();              var lstSalesRepIDs = ppdb.ProPit_User                 .Where(x => x.teamID == teamId).Select(v => v.SalesRepID).ToList();              var total = (from o in ordersQuery                             where lstSalesRepIDs.Contains(o.SalesRepID)                             select o.OrderTotal).Sum();              orderTotal += total;             dtg.DailyTotal = orderTotal;              lstDailyTeamGoal.Add(dtg);         }     }      return lstDailyTeamGoal; } 
              
 
 

Lista de respuestas

8
 
vote

Usted está llamando consultas en un bucle para cada día. Las consultas de la base de datos son lentas en comparación con la ejecución del código C #. Envíe una sola consulta al DB durante todo el rango de días.

Puede hacer la agrupación a día, ya sea como la consulta de DB o consulta los registros y el grupo desagrupados usando LINQ-TO-Objects más adelante.

También está consultando el pigLatSentence; 1 dentro del bucle. ¿Por qué? El pigLatSentence; 2 parece no cambiar entre las iteraciones de bucle. Consultarlo antes del bucle.

También su cláusula de dónde prueba los días como este: pigLatSentence; 3 . Donde pigLatSentence; 4 es un día más que pigLatSentence; 5 . Me mira como si estuvieras tomando dos días a la vez. ¿Está previsto? Si desea incluir todas las horas de un solo día, cambie la comparación con pigLatSentence; 6 . (Nota: Usé pigLatSentence; 7 en lugar de pigLatSentence; 8 para el límite superior.)

No hagas cálculos de fecha mediante la conversión de pigLatSentence; 9 a length0 y Volver! length1 contiene toda la funcionalidad que necesita, sin usar ningún truco sucio.


  length2  

length33 tiene la ventaja sobre length4 que la fuente se consume sobre la marcha, artículo por artículo. No se debe crear una lista en memoria.

El length5 requiere atención especial. Podría realizarse como parte de la consulta de DB; Sin embargo, dependiendo de la implementación y el número de length6, esto podría crear consultas con larga 9988776665443337 Listas: length8 . Hay un límite para la longitud de estas listas. Esto puede llevar a excepciones de "consulta demasiado complejos". Si este no es el caso, es decir, si sabe que siempre tendrá un número razonable de identificación, podría simplificar todo el código y hacer todo (filtrado, agrupación y resumen) con una sola consulta de DB.

 

You are calling queries in a for-loop for each day. Database queries are slow compared to C# code execution. Send only one query to the DB for the whole range of days.

You can do the grouping by day either as DB query or query the ungrouped records and group using LINQ-to-Objects later.

Also you are querying the lstSalesRepIDs within the loop. Why? The teamId seems not to change between the loop iterations. Query it before the loop.

Also your where-clause tests the days like this: o => o.DateCompleted >= dtStartDate && o.DateCompleted <= dtEndDate. Where dtEndDate is one day more than dtStartDate. It looks to me as if you were taking two days at a time. Is this intended? If you want to include all times of a single day, change the comparison to o.DateCompleted >= dtStartDate && o.DateCompleted < dtEndDate. (Note: I used < instead of <= for the upper bound.)

Don't make date calculations by converting from DateTime to string and back! DateTime contains all the functionality you need, without using any dirty tricks.


var salesRepIDs = new HashSet<int>(ppdb.ProPit_User     .Where(ppu => ppu.teamID == teamId)     .Select(ppu => ppu.SalesRepID)     .AsEnumerable()); // HashSet.Contains is faster than List.Contains.  DateTime today = DateTime.Today; DateTime startDate = new DateTime(today.Year, today.Month, 1); DateTime endDate = today.AddDays(1);  // Note: If the DB contains no entries with future dates,  //       you can drop the test for the upper date! var orders = db.Orders     .Where(o => o.DateCompleted >= startDate                 && o.DateCompleted < endDate                 && (o.Status == 1 || o.Status == 2)                 && o.Kiosk != 0)     .AsEnumerable();  // Because of AsEnumerable() we are working with LINQ-to-Objects now. var ordersByCompletionDate = orders     .Where(o => salesRepIDs.Contains(o.SalesRepID))     .GroupBy(o => o.DateCompleted.Date); // .Date in order to drop the time part. foreach (var dayGroup in ordersByCompletionDate) {     decimal daylyTotal = dayGroup.Sum(o => o.OrderTotal);     // ... } 

.AsEnumerable() has the advantage over .ToList() that the source is consumed on the fly, item by item. No in-memory list needs to be created.

The salesRepIDs.Contains(..) part requires special attention. It could be performed as part of the DB query; however depending on the implementation and the number of salesRepIDs this could create queries with long IN lists: WHERE id IN (1, 2, 3, ..). There is a limit for the length of these lists. This can lead to "Query too complex" exceptions. If this is not the case, i.e., if you know that you will always have a reasonable number of ID's, could can simplify the whole code and do everything (filtering, grouping and summing) with only one single DB query.

 
 
     
     
6
 
vote

Estoy de acuerdo con Olivier Jacot-Detcombes en los aspectos funcionales de este Código, pero también carece de organización, nombramiento significativo y coherencia, lo que lo hará más difícil para otros lectores (o en los próximos años) seguir. Algunos ejemplos:

  public static List<DailyTeamGoal> GetListDailyTeamGoals(int teamId) ... List<DailyTeamGoal> lstDailyTeamGoal = new List<DailyTeamGoal>(); ... DateTime dt = DateTime.Now; ... int days = DateTime.DaysInMonth(dt.Year, dt.Month);   

Con los idiomas modernos muy escritos como C #, agregar el 9988777665544331 a un método o nombre de variable se considera un desorden innecesario. Además, las variables con nombres poco claros se pierden en la traducción cuando se usan en otro lugar. En el último ejemplo anterior, ¿qué significa dt signico que no sea el Type de la variable? Considere estas mejoras:

  public static IEnumerable<DailyTeamGoal> GetDailyTeamGoals(int teamId) ... List<DailyTeamGoal> dailyTeamGoals = new List<DailyTeamGoal>(); ... DateTime today = DateTime.Now.Date; ... int daysThisMonth = DateTime.DaysInMonth(today.Year, today.Month);   

También hay mucho en este método. Separarlo en varios métodos con nombres claros hará que el código sea más fácil de entender y puede romper la lógica en piezas de prueba distintas. En este momento, su método único sobre cómo obtener los objetivos del equipo diario abarca una gran cantidad de lógica de negocios que será difícil de separar cuando llegue el momento (y lo hará).

 

I agree with Olivier Jacot-Descombes on the functional aspects of this code, but it also lacks organization, meaningful naming, and consistency, which will make it harder for other readers (or yourself in future years) to follow. Some examples:

public static List<DailyTeamGoal> GetListDailyTeamGoals(int teamId) ... List<DailyTeamGoal> lstDailyTeamGoal = new List<DailyTeamGoal>(); ... DateTime dt = DateTime.Now; ... int days = DateTime.DaysInMonth(dt.Year, dt.Month); 

With modern strongly typed languages like C#, adding the Type to a method or variable name is considered unnecessary clutter. Furthermore, variables with unclear names get lost in translation when used elsewhere. In the last example above, what does dt mean other than the Type of the variable? Consider these improvements:

public static IEnumerable<DailyTeamGoal> GetDailyTeamGoals(int teamId) ... List<DailyTeamGoal> dailyTeamGoals = new List<DailyTeamGoal>(); ... DateTime today = DateTime.Now.Date; ... int daysThisMonth = DateTime.DaysInMonth(today.Year, today.Month); 

There's also a lot going on in this one method. Separating it out into several methods with clear names will make the code easier to understand and can break logic out into distinct testable pieces. Right now, your single method about getting the Daily Team Goals encompasses a lot of business logic that will be hard to split out when the time comes (and it will).

 
 
     
     

Relacionados problema

2  Lógica de negocios en controlador  ( Business logic in controller ) 
LED por la premisa recientemente leída "Controladores magros y modelos de grasa" He llegado a la conclusión de que mi controlador podría ser demasiado gordo ...

1  Vista parcial para listas desplegables de uso frecuente  ( Partial view for frequently used drop down lists ) 
Tengo una entrada que se necesita en muchas formas, así que creé una vista parcial para eso. En la vista parcial, consulta la base de datos y generaré una lis...

23  ¿Cómo escribir elegantes trozos condicionales de marcado en vistas a la pista de afeitar?  ( How to write elegant conditional bits of markup in razor views ) 
Supongamos el siguiente modelo: static void Main(string[] args) { var subject = new Subject<string>(); var my = subject.GroupBy(x => x); my.S...

5  Repositorio genérico para aplicaciones web  ( Generic repository for web apps ) 
Estaba desarrollando una aplicación web usando entity Framework 6 y MVC 5. Para la capa de acceso a datos, alivié el trabajo y escribí un repositorio genérico...

14  Pruebas de repositorio y controlador  ( Repository and controller tests ) 
últimamente he estado investigando cómo la mejor unidad prueba un repositorio de EF y le ha dado un repositorio adecuadamente probado, qué para probar en el...

6  Mono alrededor con mono encuesta y ASP.NET MVC  ( Monkeying around with survey monkey and asp net mvc ) 
Intro He sido un desarrollo de escritorio durante mucho tiempo, y nunca he tenido que Mono con el desarrollo web hasta hace muy poco. Tengo la necesidad de ...

3  Master Detalle Insertar en Entity Framework 6 Base de datos Primer MVC 5  ( Master detail insert in entity framework 6 database first mvc 5 ) 
Tengo un DB con una tabla maestra llamada "Facturas" y otra tabla de detalles "Facturas_Detalle". Me gustaría insertarlos, por lo que esta es una "base de dat...

3  Seguimiento simple de usuarios en línea en ASP.NET  ( Simple tracking online users in asp net ) 
Escribí un seguimiento de usuarios simples en línea para mi proyecto ASP.NET MVC. en global.asax, agregué: protected void Session_Start(Object sender, ...

3  Carro de la compra AJAX con cantidad +/- Botones  ( Ajax shopping cart with quantity buttons ) 
Soy un desarrollador junior (Pareja de años) y muy nuevo en AJAX. Estoy escribiendo una solicitud de inventario interna construida en MVC y en este momento ...

1  Guardar datos a una sesión  ( Saving data to a session ) 
Estoy un poco confundido Si ahorrar la información al código de sesión a continuación, pertenece a la acción del controlador como se muestra a continuación o ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos