データ層に EF 4.3 を使用しており、一般的なリポジトリ パターンが用意されています。バックエンドは SQL 2008 R2 で、プロジェクトは .NET 4.0/MVC 3 ですが、これが問題の要因になるとは思いません。
基本的に、2 つのオブジェクトのデータベースには 1 対多の関係があります。1 つは「トラップ」用で、2 つ目は「トラップ アクティビティ」用です。つまり、これらの「トラップ」の 1 つが展開されると、そのトラップに発生したすべてのことがトラップ アクティビティ テーブルに保持されます。これを行うためのかなり簡単な方法である必要があります。
この関係は、「トラップ アクティビティ」テーブルの FK から「トラップ」テーブルの PK に定義されます。両方のテーブルに PK が定義されています。
私たちのサービス層では、これらのトラップが展開された日付で「トラップ」のリストを照会する必要があります。これは、次のコード スニペットによって実現されます。
var traps = this.trapRepository.Find(x => x.DeploymentYear == 2012).Select(x => new TrapHomeViewModel
{
County = x.County.Name,
DeploymentDate = x.TrapActivities.First(y => y.ActivityType == 1).ActivityDate,
State = x.County.CountyState.Abbreviation,
Latitude = x.Latitude,
Longitude = x.Longitude,
TrapId = x.TrapID,
TrapNumber = x.SerialNumber,
Centroid = x.TrapCentroid
}).ToList();
問題は、DeploymentDate プロパティに関するものです。書かれているように、これは約 3000 項目のリストを返すのに 25 秒かかります。トラップ テーブルを更新して展開日を格納し、次の行を入力します。
DeploymentDate = x.DeploymentDate.Value.Date
応答時間は 1 秒未満です。ここで何が起こっているか (データセットの複数の列挙) を知っていると思いますが、次のようなクエリになると思います。
SELECT Counties.Name, TrapActivities.ActivityDate, States.Abbreviation,
Traps.Latitude, Traps.Longitude, Traps.TrapID, Traps.SerialNumber, Traps.TrapCentroid
FROM TrapActivities INNER JOIN
Traps ON TrapActivities.TrapID = Traps.TrapID INNER JOIN
Counties ON Traps.CountyID = Counties.CountyID INNER JOIN
States ON Counties.State = States.FIPS_Code
WHERE (TrapActivities.ActivityType = 1)
…が、そうではないようです。上記のすべての背景情報を使用して、このビュー モデルを作成する際にどこに迷い込んだのでしょうか? 以前にこの問題に遭遇したことはないと思いますが、これは他のプロジェクトよりもはるかに大きなデータセットでもあります。これに関するガイダンスは非常に役立ちます。他に情報を提供する必要がある場合は、お知らせください。
編集
要求に応じて、GenericRepository Find メソッドとコンストラクター:
public class GenericRepository<T> : IGenericRepository<T>
where T : class
{
private readonly IObjectSet<T> objectSet;
private ObjectContext context;
public GenericRepository()
: this(new APHISEntities())
{
}
public GenericRepository(ObjectContext context)
{
this.context = context;
this.objectSet = this.context.CreateObjectSet<T>();
}
public IEnumerable<T> Find(Func<T, bool> predicate)
{
return this.objectSet.Where(predicate);
}
編集2
これは、上記のコードによって生成される SQL の例です。
exec sp_executesql N'SELECT
[Extent1].[TrapActivityID] AS [TrapActivityID],
[Extent1].[TrapID] AS [TrapID],
[Extent1].[ActivityType] AS [ActivityType],
[Extent1].[Notes] AS [Notes],
[Extent1].[AgentID] AS [AgentID],
[Extent1].[ActivityDate] AS [ActivityDate],
[Extent1].[CreatedOn] AS [CreatedOn],
[Extent1].[EditedOn] AS [EditedOn],
[Extent1].[Deleted] AS [Deleted],
[Extent1].[VisualInspectionID] AS [VisualInspectionID]
FROM [dbo].[TrapActivities] AS [Extent1]
WHERE [Extent1].[TrapID] = @EntityKeyValue1',N'@EntityKeyValue1 uniqueidentifier',@EntityKeyValue1='FEBC7ED4-E726-4F5E-B2BA-FFD53AB7DF34'
トラップ ID のリストを取得し、それぞれに対してクエリを実行しているように見えます。その結果、何千もの SQL ステートメントが生成されます。また、郡情報についても個別のクエリを実行しているようです。