2011-09-06 179 views
8

我有一個非常沉重的LINQ到SQL查詢,它會在不同的表上進行一些連接以返回一個匿名類型。問題是,如果返回的行數量相當大(> 200),那麼查詢變得非常緩慢並最終超時。我知道我可以增加數據上下文超時設置,但這是最後的手段。優化LINQ到SQL查詢

我只是想知道如果我的查詢會更好地工作,如果我將它分開,並做我的比較作爲LINQ到對象的查詢,所以我甚至可以使用PLINQ來最大化處理能力。但對我而言,這是一個外國概念,我無法理解我將如何分裂它。任何人都可以提供建議嗎?我並沒有要求爲我編寫代碼,只是一些關於如何改進這一點的一般指導將會很棒。

注意我已確保數據庫具有所有我正在加入的正確密鑰,並且我確保這些密鑰是最新的。

查詢低於:

var cons = (from c in dc.Consignments 
      join p in dc.PODs on c.IntConNo equals p.Consignment into pg 
      join d in dc.Depots on c.DeliveryDepot equals d.Letter 
      join sl in dc.Accounts on c.Customer equals sl.LegacyID 
      join ss in dc.Accounts on sl.InvoiceAccount equals ss.LegacyID 
      join su in dc.Accounts on c.Subcontractor equals su.Name into sug 
      join sub in dc.Accountsubbies on ss.ID equals sub.AccountID into subg 
      where (sug.FirstOrDefault() == null 
       || sug.FirstOrDefault().Customer == false) 
      select new 
      { 
       ID = c.ID, 
       IntConNo = c.IntConNo, 
       LegacyID = c.LegacyID, 
       PODs = pg.DefaultIfEmpty(), 
       TripNumber = c.TripNumber, 
       DropSequence = c.DropSequence, 
       TripDate = c.TripDate, 
       Depot = d.Name, 
       CustomerName = c.Customer, 
       CustomerReference = c.CustomerReference, 
       DeliveryName = c.DeliveryName, 
       DeliveryTown = c.DeliveryTown, 
       DeliveryPostcode = c.DeliveryPostcode, 
       VehicleText = c.VehicleReg + c.Subcontractor, 
       SubbieID = sug.DefaultIfEmpty().FirstOrDefault().ID.ToString(), 
       SubbieList = subg.DefaultIfEmpty(), 
       ScanType = ss.PODScanning == null ? 0 : ss.PODScanning 
      }); 

這裏生成的SQL的要求:

{SELECT [t0].[ID], [t0].[IntConNo], [t0].[LegacyID], [t6].[test], [t6].[ID] AS [ID2], [t6].[Consignment], [t6].[Status], [t6].[NTConsignment], [t6].[CustomerRef], [t6].[Timestamp], [t6].[SignedBy], [t6].[Clause], [t6].[BarcodeNumber], [t6].[MainRef], [t6].[Notes], [t6].[ConsignmentRef], [t6].[PODedBy], (
    SELECT COUNT(*) 
    FROM (
     SELECT NULL AS [EMPTY] 
     ) AS [t10] 
    LEFT OUTER JOIN (
     SELECT NULL AS [EMPTY] 
     FROM [dbo].[PODs] AS [t11] 
     WHERE [t0].[IntConNo] = [t11].[Consignment] 
     ) AS [t12] ON 1=1 
    ) AS [value], [t0].[TripNumber], [t0].[DropSequence], [t0].[TripDate], [t1].[Name] AS [Depot], [t0].[Customer] AS [CustomerName], [t0].[CustomerReference], [t0].[DeliveryName], [t0].[DeliveryTown], [t0].[DeliveryPostcode], [t0].[VehicleReg] + [t0].[Subcontractor] AS [VehicleText], CONVERT(NVarChar,(
    SELECT [t16].[ID] 
    FROM (
     SELECT TOP (1) [t15].[ID] 
     FROM (
      SELECT NULL AS [EMPTY] 
      ) AS [t13] 
     LEFT OUTER JOIN (
      SELECT [t14].[ID] 
      FROM [dbo].[Account] AS [t14] 
      WHERE [t0].[Subcontractor] = [t14].[Name] 
      ) AS [t15] ON 1=1 
     ORDER BY [t15].[ID] 
     ) AS [t16] 
    )) AS [SubbieID], 
    (CASE 
     WHEN [t3].[PODScanning] IS NULL THEN @p0 
     ELSE [t3].[PODScanning] 
    END) AS [ScanType], [t3].[ID] AS [ID3] 
FROM [dbo].[Consignments] AS [t0] 
INNER JOIN [dbo].[Depots] AS [t1] ON [t0].[DeliveryDepot] = [t1].[Letter] 
INNER JOIN [dbo].[Account] AS [t2] ON [t0].[Customer] = [t2].[LegacyID] 
INNER JOIN [dbo].[Account] AS [t3] ON [t2].[InvoiceAccount] = [t3].[LegacyID] 
LEFT OUTER JOIN ((
     SELECT NULL AS [EMPTY] 
     ) AS [t4] 
    LEFT OUTER JOIN (
     SELECT 1 AS [test], [t5].[ID], [t5].[Consignment], [t5].[Status], [t5].[NTConsignment], [t5].[CustomerRef], [t5].[Timestamp], [t5].[SignedBy], [t5].[Clause], [t5].[BarcodeNumber], [t5].[MainRef], [t5].[Notes], [t5].[ConsignmentRef], [t5].[PODedBy] 
     FROM [dbo].[PODs] AS [t5] 
     ) AS [t6] ON 1=1) ON [t0].[IntConNo] = [t6].[Consignment] 
WHERE ((NOT (EXISTS(
    SELECT TOP (1) NULL AS [EMPTY] 
    FROM [dbo].[Account] AS [t7] 
    WHERE [t0].[Subcontractor] = [t7].[Name] 
    ORDER BY [t7].[ID] 
    ))) OR (NOT (((
    SELECT [t9].[Customer] 
    FROM (
     SELECT TOP (1) [t8].[Customer] 
     FROM [dbo].[Account] AS [t8] 
     WHERE [t0].[Subcontractor] = [t8].[Name] 
     ORDER BY [t8].[ID] 
     ) AS [t9] 
    )) = 1))) AND ([t2].[Customer] = 1) AND ([t3].[Customer] = 1) 
ORDER BY [t0].[ID], [t1].[ID], [t2].[ID], [t3].[ID], [t6].[ID] 
} 
+4

什麼是在後臺執行的SQL?查詢計劃是什麼樣的? – Heinzi

+0

如果選擇存儲過程中的所有記錄,使用IMultilpleResults調用該記錄,然後在內存中執行聯接不會更快,我會好奇的。 – Joe

+0

您確定Linq在一個語句中完成了所有操作(並且沒有選擇每行的額外語句) - 並非100%確定在選擇新場景中是否完全可能,因此像@Heinzi所說的那樣:您需要查看SQL這是使用事件探查器生成的或記錄您的datacontext – Pleun

回答

3

嘗試將分包商聯合起來更高,與它一起推where子句。這樣你就不會不必要地進行連接,最終失敗。 我也會修改subcontractor id的select,所以你不會得到一個潛在的null值的Id。

var cons = (from c in dc.Consignments 
      join su in dc.Accounts on c.Subcontractor equals su.Name into sug 
      where (sug.FirstOrDefault() == null || sug.FirstOrDefault().Customer == false) 
      join p in dc.PODs on c.IntConNo equals p.Consignment into pg 
      join d in dc.Depots on c.DeliveryDepot equals d.Letter 
      join sl in dc.Accounts on c.Customer equals sl.LegacyID 
      join ss in dc.Accounts on sl.InvoiceAccount equals ss.LegacyID     
      join sub in dc.Accountsubbies on ss.ID equals sub.AccountID into subg 
      let firstSubContractor = sug.DefaultIfEmpty().FirstOrDefault() 
      select new 
      { 
          ID = c.ID, 
          IntConNo = c.IntConNo, 
          LegacyID = c.LegacyID, 
          PODs = pg.DefaultIfEmpty(), 
          TripNumber = c.TripNumber, 
          DropSequence = c.DropSequence, 
          TripDate = c.TripDate, 
          Depot = d.Name, 
          CustomerName = c.Customer, 
          CustomerReference = c.CustomerReference, 
          DeliveryName = c.DeliveryName, 
          DeliveryTown = c.DeliveryTown, 
          DeliveryPostcode = c.DeliveryPostcode, 
          VehicleText = c.VehicleReg + c.Subcontractor, 
          SubbieID = firstSubContractor == null ? "" : firstSubContractor.ID.ToString(), 
          SubbieList = subg.DefaultIfEmpty(), 
          ScanType = ss.PODScanning == null ? 0 : ss.PODScanning 
       });