c#linq语法因单个查询中的多个查询而变慢

时间:2014-01-16 23:16:31

标签: c# sql linq

我想知道是否有更好,更有效的方法来重新编码下面的linq语法,以使查询运行得更快,即只需调用一次数据库。我的数据库位于远程位置,导致速度很慢:

    var query = (from ticket in dataClassesDataContext.Tickets.Where(TicketsToShow.And(SearchVals))
                                select new 
                                {
                                    Priority = ticket.TicketPriority.TicketPriorityName,
                                    Ticket = string.Format(TicketFormat, ticket.TicketID),
                                    AssetId = ticket.Asset.Serial,
                                    OpenDate = ticket.CheckedInDate,
                                    OpenFor = CalculateOpenDaysAndHours(ticket.CheckedInDate, ticket.ClosedDate),
                                    Account = ticket.Account.Customer.Name,
                                    Description = ticket.Description.Replace("\n", ", "),
                                    Status = ticket.TicketStatus.TicketStatusName,
                                    Closed = ticket.ClosedDate,
  THIS IS THE CAUSE ====>>>         Amount = GetOutstandingBalanceForTicket(ticket.TicketID),
                                    Paid = ticket.Paid,
                                    Warranty = ticket.WarrantyRepair,
                                    AssetLocation = GetAssetLocationNameFromID(ticket.Asset.LocationID, AssLocNames)
                                }).Skip(totalToDisplay * page).Take(totalToDisplay);

                    if (SortOrder.ToLower().Contains("Asc".ToLower()))
                    {
                        query = query.OrderBy(p => p.OpenDate);
                    }
                    else
                    {
                        query = query.OrderByDescending(p => p.OpenDate);
                    }//ENDIF

性能不佳的主要原因是下面的函数GetOutstandingBalanceForTicket中的代码计算发票中所有项目的总和,并将其作为字符串中的总数返回:

public static string GetOutstandingBalanceForTicket(int TicketID)
{
    string result = string.Empty;
    decimal total = 0;

    try
    {
        using (DataClassesDataContext dataClassesDataContext = new DataClassesDataContext(cDbConnection.GetConnectionString()))
        {
            var queryCustomerTickets = from ticket in dataClassesDataContext.Tickets
                                       where
                                       (ticket.TicketID == TicketID)
                                       select ticket;

            if (queryCustomerTickets != null)
            {
                foreach (var ticket in queryCustomerTickets)
                {
                    var queryTicketChargeItems = from chargeItem in dataClassesDataContext.ProductChargeItems
                                                 where chargeItem.ChargeID == ticket.ChargeID &&
                                                 chargeItem.Deleted == null
                                                 select chargeItem;

                    foreach (var chargeItem in queryTicketChargeItems)
                    {
                        total += (chargeItem.Qty * chargeItem.Price);
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {

    }

    return total.ToString("0.##");
}

提前谢谢。

3 个答案:

答案 0 :(得分:2)

正如您所指出的,此代码非常慢,因为每个故障单都需要进行查询。

为了消除对多个查询的需要,您应该考虑在ticketsToShow和故障单实体之间应用内部联接(在ticketid上),使用groupby提供每张故障单的费用总和。

LINQ: Using INNER JOIN, Group and SUM

的答案中详细说明了这一点

答案 1 :(得分:0)

理想情况下,您可能会更多地将其作为一次性设置的急切加载。但是,我认为linq2sql不支持(我知道EF会这样做)。您可以做的一件事是避免嵌套查询。由于您已经可以访问故障单表,或许您应该从Sum()语句中发出select。我很难验证这是否有任何改进,所以如果你愿意的话,这段代码就会出现。

 //(from ticket in dataClassesDataContext.Tickets.Where(TicketsToShow.And(SearchVals))
 (from ticket in dataClassesDataContext.Tickets
//this would be where you could eager load if possible (not entirely required)
//.Include is an EF method used only as example
/*.Include(t => t.TicketPriority)//eager load required entities
 .Include(t => t.Asset)//eager load required entities
 .Include(t => t.Account.Customer)//eager load required entities
 .Include(t => t.TicketStatus)//eager load required entities
 .Include(t => t.ProductChargeItems)//eager load required entities
*/
 .Where(TicketsToShow.And(SearchVals))
   select new 
   {
       Priority = ticket.TicketPriority.TicketPriorityName,
       Ticket = string.Format(TicketFormat, ticket.TicketID),
       AssetId = ticket.Asset.Serial,
       OpenDate = ticket.CheckedInDate,
       OpenFor = CalculateOpenDaysAndHours(ticket.CheckedInDate, ticket.ClosedDate),
       Account = ticket.Account.Customer.Name,
       Description = ticket.Description.Replace("\n", ", "),
       Status = ticket.TicketStatus.TicketStatusName,
       Closed = ticket.ClosedDate,
       //Use Sum and the foreign relation instead of a nested query
       Amount = ticket.ProductChargeItems.Where(pci => pci.Deleted == null).Sum(pci => pci.Qty * pci.Price),
       Paid = ticket.Paid,
       Warranty = ticket.WarrantyRepair,
       AssetLocation = GetAssetLocationNameFromID(ticket.Asset.LocationID, AssLocNames)
   }).Skip(totalToDisplay * page).Take(totalToDisplay);

   if (SortOrder.ToLower().Contains("Asc".ToLower()))
   {
       query = query.OrderBy(p => p.OpenDate);
   }
   else
   {
       query = query.OrderByDescending(p => p.OpenDate);
   }

答案 2 :(得分:0)

我认为,您可以简化此查询。有人这样想:

public static string GetOutstandingBalanceForTicket(DataClassesDataContext context, int TicketID)
{
    decimal total = 0;

    var total = (from ticket in context.Tickets
                 join chargeItem from context.ProductChargeItems on chargeItem.ChargeID == ticket.ChargeID
                 where (ticket.TicketID == TicketID && chargeItem.Deleted == null)
                 select chargeItem).Sum(chargeItem => chargeItem.Qty * chargeItem.Price);


    return total.ToString("0.##");
}
/*...*/
Amount = GetOutstandingBalanceForTicket(dataClassesDataContext, ticket.TicketID),

现在,您可以在查询中内联此方法。

它可能包含语法错误,因为我在记事本中写了它。