3

私が使用しているこのlinqクエリがあり、asp.netアプリケーションを実行しているときに実行に50秒かかりますが、LinqPadおよびSql Management Studioでは同じクエリが500ミリ秒で実行されます。

SQL プロファイラーからクエリを取得し、SQL Management Studio で再度実行したところ、約 500 ミリ秒かかりました。余分な 49 秒という、Linq のオーバーヘッドは何をしているでしょうか??

以下、参考コードです、よろしくお願いします。

var rCampaign =
    (from a in db.AdCreative
     join h in db.AdHit on a.ID equals h.AdID into gh
     join l in db.AdGroup_Location on a.AdGroupID equals l.AdGroupID into gj
     from subloc in gj.DefaultIfEmpty()
     from subhits in gh.DefaultIfEmpty()
     where a.AdGroup.AdHost.Select(q => q.ID).Contains(rPlatform.ID) &&
           a.AdGroup.AdPublisher.Select(q => q.ID).Contains(rPublisher.ID) &&
           a.AdDimensionID == AdSize &&
           a.AdGroup.Campaign.Starts <= rNow &&
           a.AdGroup.Campaign.Ends >= rNow &&
           subhits.HitType == 1 &&
           (subloc == null || subloc.LocationID == rLocationID)
     select new {
         ID = a.ID,
         Name = a.Name,
         Spent = (subhits.AdDimension != null) ? ((double)subhits.AdDimension.Credit / 1000) : 0,
         CampaignID = a.AdGroup.Campaign.ID,
         CampaignName = a.AdGroup.Campaign.Name,
         CampaignBudget = a.AdGroup.Campaign.DailyBudget
     }).GroupBy(adgroup => adgroup.ID)
       .Select(adgroup => new {
           ID = adgroup.Key,
           Name = adgroup.FirstOrDefault().Name,
           Spent = adgroup.Sum(q => q.Spent),
           CampaignID = adgroup.FirstOrDefault().CampaignID,
           CampaignName = adgroup.FirstOrDefault().CampaignName,
           CampaignBudget = adgroup.FirstOrDefault().CampaignBudget,
       })
      .GroupBy(q => q.CampaignID)
      .Select(campaigngroup => new {
          CampaignID = campaigngroup.Key,
          DailyBudget = campaigngroup.FirstOrDefault().CampaignBudget,
          Consumed = campaigngroup.Sum(q => q.Spent),
          RemainningCredit = campaigngroup.FirstOrDefault().CampaignBudget - campaigngroup.Sum(q => q.Spent),
          Ads = campaigngroup.Select(ag => new {
              ID = ag.ID,
              Name = ag.Name,
              Spent = ag.Spent
          }).OrderBy(q => q.Spent)
      })
      .Where(q => q.Consumed <= q.DailyBudget).OrderByDescending(q => q.RemainningCredit).First();
4

2 に答える 2

1

クエリ構文を使用してリファクタリングしました(読みやすさが向上したかどうかはわかりません)。によって1つのグループを削除しました。いくつかの小さな調整を行いました(FirstOrDefaultをKeyプロパティに置き換え、ContainsをAnyに変更しました)。うまくいけば、それは速度の効果があります。

 var rCampaign = (from cg in 
                   (from a in db.AdCreative
                    from subhits in db.AdHit.Where(h => a.ID == h.AdID)
                                            .DefaultIfEmpty()
                    from subloc in db.AdGroup_Location.Where(l => a.AdGroupID == l.AdGroupID)
                                                      .DefaultIfEmpty()
                    where a.AdGroup.AdHost.Any(q => q.ID == rPlatform.ID) &&
                          a.AdGroup.AdPublisher.Any(q => q.ID == rPublisher.ID) &&
                          a.AdDimensionID == AdSize &&
                          a.AdGroup.Campaign.Starts <= rNow &&
                          a.AdGroup.Campaign.Ends >= rNow &&
                          subhits.HitType == 1 &&
                          (subloc == null || subloc.LocationID == rLocationID)
                    group new { a, subhits } by new { ID = a.ID, a.Name, CampaignID = a.AdGroup.Campaign.ID, CampaignName = a.AdGroup.Campaign.Name, CampaignBudget = a.AdGroup.Campaign.DailyBudget } into g
                    select new 
                    {
                      ID = g.Key.ID,
                      Name = g.Key.Name,
                      Spent = g.Sum(x => (x.subhits.AdDimension != null) ? ((double)subhits.AdDimension.Credit / 1000) : 0),
                      CampaignID = g.Key.CampaignID,
                      CampaignName = g.Key.CampaignName,
                      CampaignBudget = g.Key.CampaignBudget                                    
                   })
                 group cg by new { cg.CampaignID, cg.CampaignBudget } into cg
                 let tempConsumed = cg.Sum(q => q.Spent)
                 let tempRemainningCredit = cg.Key.CampaignBudget - tempConsumed
                 where tempConsumed <= cg.Key.CampaignBudget
                 orderby tempRemainningCredit desc
                 select new
                 {
                   CampaignID = cg.Key.CampaignID,
                   DailyBudget = cg.Key.CampaignBudget,
                   Consumed = tempConsumed,
                   RemainningCredit = tempRemainningCredit,
                   Ads = from ag in cg
                         orderby ag.Spent
                         select new
                         {
                           ID = ag.ID,
                           Name = ag.Name,
                           Spent = ag.Spent
                          }
                  }).First();
于 2012-10-11T15:01:54.953 に答える
1

そのクエリを簡略化する方法がいくつかあります。

  • select intoすべてをクエリ構文に保持できます。
  • //左結合を実装するコンストラクトはjoin ... into、グループ結合を表すコンストラクトに置き換えることができますfromDefaultIfManyjoin ... into
  • 末尾近くのグループの一部は空にできないため、FirstOrDefault不要です。
  • クエリが複雑になる前に、一部のwhere条件を一番上に移動できます。

これが私が取った刺し傷です。改訂は重要だったので、少しデバッグが必要かもしれません:

var rCampaign = ( 
    from a in db.AdCreative

    where a.AdDimensionID == AdSize &&
          a.AdGroup.Campaign.Starts <= rNow &&
          a.AdGroup.Campaign.Ends >= rNow &&
          a.AdGroup.AdHost.Select(q => q.ID).Contains(rPlatform.ID) &&
          a.AdGroup.AdPublisher.Select(q => q.ID).Contains(rPublisher.ID)

    join hit in db.AdHit.Where(h => h.HitType == 1 && h.LocationID == rLocationID)
        on a.ID equals hit.AdID
        into hits

    join loc in db.AdGroup_Location
        on a.AdGroupID equals loc.AdGroupID
        into locs

    where !locs.Any() || locs.Any(l => l.LocationID == rLocationID)

    select new {
        a.ID,
        a.Name,
        Spent = hits.Sum(h => h.AdDimension.Credit / 1000) ?? 0,
        CampaignID = a.AdGroup.Campaign.ID,
        CampaignName = a.AdGroup.Campaign.Name,
        CampaignBudget = a.AdGroup.Campaign.DailyBudget,
    } into adgroup
    group adgroup by adgroup.CampaignID into campaigngroup
    select new
    {
        CampaignID = campaigngroup.Key,
        DailyBudget = campaigngroup.First().CampaignBudget,
        Consumed = campaigngroup.Sum(q => q.Spent),
        RemainingCredit = campaigngroup.First().CampaignBudget - campaigngroup.Sum(q => q.Spent),
        Ads = campaigngroup.Select(ag => new {
            ag.ID,
            ag.Name,
            ag.Spent,
        }).OrderBy(q => q.Spent)
    } into q
    where q.Consumed <= q.DailyBudget
    orderby q.RemainingCredit desc)
    .First()
于 2012-10-11T15:17:42.870 に答える