2010-10-06 47 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

相關問題