2015-12-13 75 views
-1

我寫這樣的查詢:優化LINQ EF。使用哪裏而不是聯接?

using (var _db = new LuxedecorContext()) 
      { 
       var items = (from navItem in _db.NavItems 
          join dealItem in _db.Deal_Items 
          on navItem.ItemWebCode equals dealItem.ItemWebCode 
          join mainCategory in _db.Web_MainCategory 
          on new { A = navItem.Website, B = navItem.MainCategory } 
          equals new { A = mainCategory.Website, B = mainCategory.Code } 
          join subCategory in _db.Web_SubCategory 
          on new { A = navItem.Website, B = navItem.MainCategory, C = navItem.SubCategory } 
          equals new { A = subCategory.Website, B = subCategory.CodeMain, C = subCategory.Code } 
          select new 
          { 
           SalePrice = navItem.SalePrice, 
           Vendor = navItem.Vendor, 
           Promo = navItem.Promo, 
           Description = navItem.Description, 
           FreightMax = navItem.FreightMax, 
           ItemImage = navItem.ItemImage, 
           ItemImage2 = navItem.ItemImage2, 
           StrikedPrice = (navItem.RetailPrice ?? 0) * (1 - (navItem.PercentOff ?? 0)/100)/(1 - navItem.PercentOffShow/100), 
           ItemId = navItem.ItemID,  
           StockQty = navItem.StockQty, 
           SeoURL = navItem.SeoURL,         
           DealSequence = dealItem.Sequence, 
           DealId = dealItem.DealID, 
           Website = navItem.Website 
          }).Where(x => x.SeoURL != string.Empty && x.DealId == dealId).GroupBy(x=>x.ItemId).Select(x=>x.FirstOrDefault()); 


       if(onlyAvalaibleItems) 
        items = items.Where(x => x.StockQty != "0"); 

       switch(sort) 
       { 
        case "PriceAsc": 
         items = items.OrderBy(x => x.SalePrice); 
         break; 
        case "PriceDesc": 
         items = items.OrderByDescending(x => x.SalePrice); 
         break; 
        case "DescriptionAsc": 
         items = items.OrderBy(x => x.Description.Replace(x.Vendor, "").Trim()); 
         break; 
        case "DescriptionDesc": 
         items = items.OrderByDescending(x => x.Description.Replace(x.Vendor, "").Trim()); 
         break; 
        default: 
         items = items.OrderBy(x=>x.DealSequence); 
         break; 
       } 

       return await items.Select(x => new ProductCollectionItem 
       { 
        SalePrice = x.SalePrice, 
        Vendor = x.Vendor, 
        Promo = x.Promo, 
        Description = x.Description, 
        FreightMax = x.FreightMax, 
        ItemImage = x.ItemImage, 
        ItemImage2 = x.ItemImage2, 
        StrikedPrice = x.StrikedPrice ?? 0 
       }).ToListAsync(); 
      } 

這是SQL,我已經有了:

SELECT 
[Project4].[C1] AS [C1], 
[Project4].[SalePrice] AS [SalePrice], 
[Project4].[Vendor] AS [Vendor], 
[Project4].[Promo] AS [Promo], 
[Project4].[Description] AS [Description], 
[Project4].[FreightMax] AS [FreightMax], 
[Project4].[ItemImage] AS [ItemImage], 
[Project4].[ItemImage2] AS [ItemImage2], 
[Project4].[C2] AS [C2] 
FROM (SELECT 
    1 AS [C1], 
    CASE WHEN ([Limit1].[C1] IS NULL) THEN cast(0 as decimal(18)) ELSE [Limit1].[C1] END AS [C2], 
    [Limit1].[Description] AS [Description], 
    [Limit1].[SalePrice] AS [SalePrice], 
    [Limit1].[ItemImage] AS [ItemImage], 
    [Limit1].[ItemImage2] AS [ItemImage2], 
    [Limit1].[Vendor] AS [Vendor], 
    [Limit1].[Promo] AS [Promo], 
    [Limit1].[FreightMax] AS [FreightMax], 
    [Limit1].[Sequence] AS [Sequence] 
    FROM (SELECT 
     @p__linq__0 AS [p__linq__0], 
     @p__linq__1 AS [p__linq__1], 
     [Distinct1].[ItemID] AS [ItemID] 
     FROM (SELECT DISTINCT 
      [Extent1].[ItemID] AS [ItemID] 
      FROM [dbo].[NavItems] AS [Extent1] 
      INNER JOIN [dbo].[Deal_Items] AS [Extent2] ON [Extent1].[ItemWebCode] = [Extent2].[ItemWebCode] 
      INNER JOIN [dbo].[Web_MainCategory] AS [Extent3] ON ([Extent1].[Website] = [Extent3].[Website]) AND ([Extent1].[MainCategory] = [Extent3].[Code]) 
      INNER JOIN [dbo].[Web_SubCategory] AS [Extent4] ON ([Extent1].[Website] = [Extent4].[Website]) AND ([Extent1].[MainCategory] = [Extent4].[CodeMain]) AND ([Extent1].[SubCategory] = [Extent4].[Code]) 
      WHERE (NOT (([Extent1].[SeoURL] = @p__linq__0) AND ((CASE WHEN ([Extent1].[SeoURL] IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END) = (CASE WHEN (@p__linq__0 IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END)))) AND ([Extent2].[DealID] = @p__linq__1) 
     ) AS [Distinct1]) AS [Project2] 
    OUTER APPLY (SELECT TOP (1) 
     [Extent5].[Description] AS [Description], 
     [Extent5].[SalePrice] AS [SalePrice], 
     [Extent5].[ItemImage] AS [ItemImage], 
     [Extent5].[ItemImage2] AS [ItemImage2], 
     [Extent5].[Vendor] AS [Vendor], 
     [Extent5].[Promo] AS [Promo], 
     [Extent5].[FreightMax] AS [FreightMax], 
     [Extent6].[Sequence] AS [Sequence], 
     ((CASE WHEN ([Extent5].[RetailPrice] IS NULL) THEN cast(0 as decimal(18)) ELSE [Extent5].[RetailPrice] END) * (cast(1 as decimal(18)) - ((CASE WHEN ([Extent5].[PercentOff] IS NULL) THEN cast(0 as decimal(18)) ELSE [Extent5].[PercentOff] END)/cast(100 as decimal(18)))))/(cast(1 as decimal(18)) - ([Extent5].[PercentOffShow]/cast(100 as decimal(18)))) AS [C1] 
     FROM [dbo].[NavItems] AS [Extent5] 
     INNER JOIN [dbo].[Deal_Items] AS [Extent6] ON [Extent5].[ItemWebCode] = [Extent6].[ItemWebCode] 
     INNER JOIN [dbo].[Web_MainCategory] AS [Extent7] ON ([Extent5].[Website] = [Extent7].[Website]) AND ([Extent5].[MainCategory] = [Extent7].[Code]) 
     INNER JOIN [dbo].[Web_SubCategory] AS [Extent8] ON ([Extent5].[Website] = [Extent8].[Website]) AND ([Extent5].[MainCategory] = [Extent8].[CodeMain]) AND ([Extent5].[SubCategory] = [Extent8].[Code]) 
     WHERE (NOT (([Extent5].[SeoURL] = @p__linq__0) AND ((CASE WHEN ([Extent5].[SeoURL] IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END) = (CASE WHEN (@p__linq__0 IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END)))) AND ([Extent6].[DealID] = @p__linq__1) AND ([Project2].[ItemID] = [Extent5].[ItemID])) AS [Limit1] 
) AS [Project4] 
ORDER BY [Project4].[Sequence] ASC 

沒有在舊的數據庫的任何關係。我正在使用大部分連接來剪切我不需要的數據。我想知道:這是一個好方法嗎?我怎樣才能優化我的查詢?

+0

後的實際執行,目前的表現和PERF目標。 – usr

回答

1

我總是不喜歡使用連接進行過濾。由於兩個原因:

  • 連接可能會使結果倍增(如果連接的表格處於1:n關聯中),則必須使結果不同。這在性能方面可能是一個令人信服的理由。
  • Join傳達您想擴展連接表中字段的結果集。另一方面,(或SQL中的EXISTS)正好表達了你想要的內容:過濾。換句話說:使用讓你的代碼不言自明的方法。

如果你只有與1..n-1關聯的連接(我認爲),只有第二個原因是重要的,因爲性能應該差別不大。對我來說,第二個理由雖然足夠引人注目。注意:即使數據庫沒有硬外鍵,我強烈建議你在EF模型中定義關聯(導航屬性)。如果你這樣做,你可以使用如下代碼

from navItem in _db.NavItems 
where navItem.DealItem != null 

鍵和外鍵拉(僞)入類模型的屬性,所以你可以做

from navItem in _db.NavItems 
where navItem.ItemWebCode.HasValue