2011-09-06 229 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 
       });