2010-10-06 66 views
0

我有下面的LINQ to SQL方法需要过多的时间来执行,但其SQL对手是相当简单和快速。我在LINQ部分做错了什么?我只是试图在数据网格中返回一些数据以显示,只读。为什么这个LINQ比SQL对应的要慢得多?

我明白,如果该工具不适合不要使用它,因此我可以在这里做一个SQL调用,但我想了解为什么会有这样的差异。

下面是LINQ,然后是它转储的SQL。

public static DataTable GetEnrolledMembers(Guid workerID) 
    { 
     using (var DB = CmoDataContext.Create()) 
     {     
      var AllEnrollees = from enrollment in DB.tblCMOEnrollments 
           where enrollment.CMOSocialWorkerID == workerID || enrollment.CMONurseID == workerID 
           join supportWorker in DB.tblSupportWorkers on enrollment.EconomicSupportWorkerID 
            equals supportWorker.SupportWorkerID into workerGroup 
           from worker in workerGroup.DefaultIfEmpty() 
           select 
            new 
             { 
              enrollment.ClientID, 
              enrollment.CMONurseID, 
              enrollment.CMOSocialWorkerID, 
              enrollment.EnrollmentDate, 
              enrollment.DisenrollmentDate, 
              ESFirstName = worker.FirstName, 
              ESLastName = worker.LastName, 
              ESPhone = worker.Phone 
             }; 

      var result = from enrollee in AllEnrollees.AsEnumerable() 
         where (enrollee.DisenrollmentDate == null || enrollee.DisenrollmentDate > DateTime.Now) 
         let lastName = BLLConnect.MemberLastName(enrollee.ClientID) 
         let firstName = BLLConnect.MemberFirstName(enrollee.ClientID) 
         orderby enrollee.DisenrollmentDate ascending , lastName ascending 
         select new 
          { 
           enrollee.ClientID, 
           LastName = lastName, 
           FirstName = firstName, 
           NurseName = BLLAspnetdb.NurseName(enrollee.CMONurseID), 
           SocialWorkerName = BLLAspnetdb.SocialWorkerName(enrollee.CMOSocialWorkerID), 
           enrollee.EnrollmentDate, 
           enrollee.DisenrollmentDate, 
           ESWorkerName = enrollee.ESFirstName + " " + enrollee.ESLastName, 
           enrollee.ESPhone 
          }; 

      DB.Log = Console.Out; 
      return result.CopyLinqToDataTable(); 
     } 
    } 

和SQL:

SELECT [t0].[ClientID], [t0].[CMONurseID], [t0].[CMOSocialWorkerID], [t0].[EnrollmentDate], [t0].[DisenrollmentDate], [t1].[FirstName] AS [ESFirstName], [t1].[LastName] AS [ESLastName], [t1].[Phone] AS [ESPhone] 
FROM [dbo].[tblCMOEnrollment] AS [t0] 
LEFT OUTER JOIN [dbo].[tblSupportWorker] AS [t1] ON [t0].[EconomicSupportWorkerID] = ([t1].[SupportWorkerID]) 
WHERE ([t0].[CMOSocialWorkerID] = @p0) OR ([t0].[CMONurseID] = @p1) 
-- @p0: Input UniqueIdentifier (Size = 0; Prec = 0; Scale = 0) [060632ee-be09-4057-b17b-2d0190d0ff74] 
-- @p1: Input UniqueIdentifier (Size = 0; Prec = 0; Scale = 0) [060632ee-be09-4057-b17b-2d0190d0ff74] 
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.4926 

回答

1

首先,我不认为你是在比较苹果和苹果,你有很多BllConnect.Something调用选择第二个linq查询。此外,您必须按照其他答案中提到的方法取出AsEnumerable。

考虑以下(给你加在db和/或LINQ2SQL设计师的对应关系):

public static DataTable GetEnrolledMembers(Guid workerID) 
{ 
    using (var DB = CmoDataContext.Create()) 
    {     
     var AllEnrollees = from enrollment in DB.tblCMOEnrollments 
          where enrollment.CMOSocialWorkerID == workerID 
           || enrollment.CMONurseID == workerID 
          let w = enrollment.EconomicSupporterWorker 
          select new 
            { 
             enrollment.ClientID, 
             enrollment.CMONurseID, 
             enrollment.CMOSocialWorkerID, 
             enrollment.EnrollmentDate, 
             enrollment.DisenrollmentDate, 
             ESFirstName = w != null ? w.FirstName : null, 
             ESLastName = w != null ? w.LastName : null, 
             ESPhone = w != null ? w.Phone : null 
            }; 
     var filteredEnrollees = AllEnrollees 
      .Where(e=> e.DisenrollmentDate == null || e.DisenrollmentDate > DateTime.Now); 
     //benchmark how much it delays if you do a .ToList until here 
     // ... when comparing the sql, run it on the same remote computer you are running this, 
     // so you take into account the time to transfer the data. 
     filteredEnrollees = filteredEnrollees 
      .OrderBy(e=> e.DisenrollmentData) // benchmark here again 
      .ThenBy(e=> BLLConnect.MemberLastName(enrollee.ClientID)); // prob. causing issues 
     var result = // do what you already had, but against filteredEnrollees and benchmark 
     // prob. issues with BllConnect.* and BllAspnetdb.* being called for each record/
     // ... doesn't happen in sql side 

     DB.Log = Console.Out; 
     return result.CopyLinqToDataTable(); 
    } 
} 
+0

谢谢你的帮助。你是对的,'BLLConnect.MemberLastName()'在你的文章中造成问题,说没有SQL对应。另外,我不确定你想用'workerGroup.DefaultIfEmpty()'中的工作人员向我展示什么。' – 2010-10-06 18:40:56

+0

刚刚编辑出'from workerGroup.DefaultIfEmpty()'/那里是mystake。 Re BllConnect.MemberLastName(),这就是当你取出AsEnumerable时应该得到的版本。这正是问题所在,通过使用AsEnumerable或任何您可能正在做的事情,您正在导致在服务器上执行linq查询的一部分。 – eglasius 2010-10-06 18:48:26

+0

我建议用它的内联等效替换BLLConnect.MemberLastName,所以linq2sql在sql方面做它。另外请确保您以后所做的任何调用都不会再次打到任何外部资源/数据库,因为这些将调用每行。 – eglasius 2010-10-06 18:50:56

4

通过添加AsEnumerable()

var result = from enrollee in AllEnrollees.AsEnumerable() 
      ... 

你迫使第一查询被完全评价,每一条记录(AllEnrollees)要取来自DB。

用你的SQL语句,你正在做的所有服务器上的过滤,这将更快。

+0

我明白了,我应该张贴关于如何返工我的LINQ语句的正确方法第二个问题? – 2010-10-06 17:25:02

+0

@Refracted:可能。您可以尝试删除“AsEnumerable”,并查看您的提供者是否可以从查询中理解 - 这可能是所有必需的。 – 2010-10-06 17:32:19

+0

我删除了'AsEnumerable()',因此,第二部分中有两个'let'。可悲的是,它现在甚至还在运行之前运行! – 2010-10-06 17:50:07

相关问题