2011-09-06 18 views
8

非常に重いLINQ-to-SQLクエリがあります。匿名型を返すために、さまざまなテーブルに多数の結合が行われます。問題は、返される行の量がかなり大きい(> 200)場合、クエリは非常に遅くなり、タイムアウトに終わります。私は、データコンテキストタイムアウトの設定を増やすことができますが、それは最後の手段です。LINQ-to-SQLクエリの最適化

分割して比較するとクエリがうまく機能するかどうか、LINQ-to-Objectsクエリとして比較するので、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が1つのステートメントですべてを実行していることを確認しています(行ごとに余分なステートメントが選択されているわけではありません)。もし新しいシナリオが選択されていれば100%確信していないので、@Heinziは言った:プロファイラを使用して生成されるか、データコンテキストをログに記録する – Pleun

答えて

3

は高いアップに参加下請けを動かしてみて、それに伴い、where句を押してください。そうすれば、最後に不合格になる結合を不必要に作成することにはなりません。 また、私は潜在的なNULL値のIdを取得しないように、下請け業者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 
       });