2011-01-18 32 views
8

Entity Framework 4.0ベースのデータベースレイヤーをプロファイリングした後、エンティティが既にデータベースに存在するかどうかを確認するために使用する単純なLINQ Any() Any()チェックでは、エンティティを保存するよりも処理速度が遅くなります。 データベースに比較的少数の行があり、チェック対象の列が索引付けされています。Entity FrameworkでのLINQ Any()呼び出しの最適化

私は設定グループの存在を確認するには、次のLINQを使用します。

exec sp_executesql N'SELECT 
CASE WHEN (EXISTS (SELECT 
    1 AS [C1] 
    FROM [dbo].[SettingGroups] AS [Extent1] 
    WHERE ([Extent1].[Group] = @p__linq__0) AND ([Extent1].[Category] = @p__linq__1) 
)) THEN cast(1 as bit) WHEN (NOT EXISTS (SELECT 
    1 AS [C1] 
    FROM [dbo].[SettingGroups] AS [Extent2] 
    WHERE ([Extent2].[Group] = @p__linq__0) AND ([Extent2].[Category] = @p__linq__1) 
)) THEN cast(0 as bit) END AS [C1] 
FROM (SELECT 1 AS X) AS [SingleRowTable1]',N'@p__linq__0 nvarchar(4000),@p__linq__1 nvarchar(4000)',@p__linq__0=N'Cleanup',@p__linq__1=N'Mediator' 

from sg in context.SettingGroups 
where sg.Group.Equals(settingGroup) && sg.Category.Equals(settingCategory) 
select sg).Any() 

これは、次のSQLを(さらに私のSQLプロファイラは、クエリが2回実行されたと主張)を生成

今私はこの問題を解決するためにストアドプロシージャを作成することしか考えられませんが、もちろんLINQにコードを保存することをお勧めします。

このような「Exist」チェックをEFでより速く実行する方法はありますか?

私はおそらく、n-tierアーキテクチャで自己追跡エンティティも使用すると言います。いくつかのシナリオでは、一部のエンティティのChangeTracker状態は、データベースにすでに存在していても「追加」に設定されています。このため、データベースを更新すると挿入エラーの例外が発生した場合に、チェックを使用してChangeTrackerの状態を変更します。

答えて

0

問題はEntity Framework(少なくともEF4)が愚かなSQLを生成していることです。次のコードは、最小限の痛みでまともなSQLを生成するようです。

public static class LinqExt 
{ 
    public static bool BetterAny<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate) 
    { 
     return queryable.Where(predicate).Select(x => (int?)1).FirstOrDefault().HasValue; 
    } 

    public static bool BetterAny<T>(this IQueryable<T> queryable) 
    { 
     return queryable.Select(x => (int?)1).FirstOrDefault().HasValue; 
    } 

} 

次に、あなたが行うことができます:

(from sg in context.SettingGroups 
where sg.Group.Equals(settingGroup) && sg.Category.Equals(settingCategory) 
select sg).BetterAny() 

かさえを:

context.SettingGroups.BetterAny(sg => sg.Group.Equals(settingGroup) && sg.Category.Equals(settingCategory)); 
0

私はそれが悲惨な解決策に思えますが、Anyの代わりにCountを使用するとどうなりますか?

+0

私はそれを試してみるだろう。 – Holstebroe

0

生成されたselect文を実行する時間をプロファイリングして、期待どおりの/実行したいものを選択したことがありますか?それは見た目ほど悪くない可能性があります。

セクション

SELECT 
1 AS [C1] 
FROM [dbo].[SettingGroups] AS [Extent1] 
WHERE ([Extent1].[Group] = @p__linq__0) AND ([Extent1].[Category] = @p__linq__1) 

は、おそらくあなたが産生されることが期待されるものに近いです。クエリオプティマイザは、2番目のクエリが最初のクエリと同じであることを認識し、クエリ全体にほとんど時間を追加しない可能性があります。

1

データベーステーブル "SettingGroups"にグループを追加してみてください。&カテゴリ。

これは同様のSQLを生成しますか?

var ok = context.SettingGroups.Any(sg => sg.Group==settingGroup && sg.Category==settingCategory); 
+0

はい、インデックスを使用してください。 SettingGroups(グループ、カテゴリ)でインデックスIX_SettingGroups_GCを作成します。 – Ben

関連する問題