3

私はこのSQLクエリを持っています:

select 
    sum(h.nbHeures) 
from 
    Heures h
join 
    HeuresProjets hp on h.HpGuid=hp.HPId
join 
    ActivityCodes ac on h.Code=ac.ActivityId
join 
    MainDoeuvre mdo on ac.ActivityId=mdo.CodeGuid
where 
    hp.ExtraGuid = '61E931C8-3268-4C9C-9FF5-ED0213D348D0' 
    and mdo.NoType = 1

1 秒もかからずに実行されます。これは優れています。私のプロジェクトでは、LINQ to entities を使用してデータを取得しています。この (SQL に非常に似た) クエリは非常に遅く、1 分以上かかります。

  var result = (from hp in this.HeuresProjets
                join h in ctx.Heures on hp.HPId equals h.HpGuid
                join ac in ctx.ActivityCodes on h.Code equals ac.ActivityId
                join mdo in ctx.MainDoeuvre on ac.ActivityId equals mdo.CodeGuid
                where hp.ExtraGuid == this.EntityGuid && mdo.NoType == (int)spType
                select h.NbHeures).Sum();
  total = result; 

代わりにネストされたループを使用してみました。高速ですが、それでも遅いです (~15 秒)。

foreach (HeuresProjets item in this.HeuresProjets)
{
         foreach (Heures h in ctx.Heures.Where(x => x.HpGuid == item.HPId))
         {
               if (h.ActivityCodes != null && h.ActivityCodes.MainDoeuvre.FirstOrDefault() != null && h.ActivityCodes.MainDoeuvre.First().NoType == (int)type)
               {
                      total += h.NbHeures;
               }
          }
}

私は明らかに間違ったことをしていますか?これを最適化する方法がない場合は、ストアド プロシージャを呼び出すだけですが、コード内のロジックを維持したいと考えています。

編集

IronMan84 のアドバイスに従ってクエリを修正しました。

decimal total = 0;

var result = (from hp in ctx.HeuresProjets
              join h in ctx.Heures on hp.HPId equals h.HpGuid
              join ac in ctx.ActivityCodes on h.Code equals ac.ActivityId
              join mdo in ctx.MainDoeuvre on ac.ActivityId equals mdo.CodeGuid
              where hp.ExtraGuid == this.EntityGuid && mdo.NoType == (int)spType
              select h);

if(result.Any())
  total = result.Sum(x=>x.NbHeures);

これはほとんど機能します。高速に実行され、10 進数が返されますが、
1. 正しい値ではありません
2. 異なるパラメーターでまったく同じ値が返されるため、結果は明確にキャッシュされます。

4

1 に答える 1

3

あなたのコードを見ると、あなたのクエリは、あなたが参加しているテーブルからすべてのレコードを取得していると思います(したがって、長い時間がかかります)。を使用しているのを見ていますがthis.HeuresProjets、これは、データベースから既に取得したデータベース オブジェクトのコレクションであると想定しています (それが を使用していない理由ですctx.HeuresProjets)。したがって、そのコレクションは、結合クエリに到達するまでに、おそらく既にハイドレートされています。その場合、LINQ-To-Objects クエリになり、結合を完了するために EF が他のすべてのテーブルのレコードを取得する必要があります。

私の仮定が正しいと仮定すると(間違っている場合はお知らせください)、これを試してみてください。

var result = (from hp in ctx.HeuresProjets
                join h in ctx.Heures on hp.HPId equals h.HpGuid
                join ac in ctx.ActivityCodes on h.Code equals ac.ActivityId
                join mdo in ctx.MainDoeuvre on ac.ActivityId equals mdo.CodeGuid
                where hp.ExtraGuid == this.EntityGuid && mdo.NoType == (int)spType
                select h).Sum(h => h.NbHeures);
total = result; 

また、this.HeuresProjets特定のオブジェクトのみのフィルタリングされたリストである場合はwhere、クエリの句に追加して、ID が確実に含まれるようにすることができます。this.HeuresProjets.Select(hp => hp.HPId)

于 2013-04-05T19:29:00.590 に答える