2010-12-28 8 views
1

私はムービーストアのWebサイト(ASP.NET、EF4、SQL Server 2008を使用)に何か設定しようとしています。私のシナリオでは、 "Member"ストアがActorName、MovieTitle、およびCatalogNumberを含むテキストファイルには、次のようにEF4何千ものレコードをインポート/ルックアップ - 私のパフォーマンスが悪臭を放つ!

俳優、映画、CatalogNumber
ジョン・ウェイン、勇気ある追跡、4577から12(レコードごとに繰り返される)

このデータはに使用されますが俳優や映画を検索し、「MemberMovie」レコードを作成します。これらのテーブルを使用して100以上のレコードをインポートすると、インポート速度がひどいです:

  • 俳優表:フィールド= {ID、名前、等}
  • 映画表:フィールド= {ID、タイトル、アクターID、等}
  • MemberMovie表:フィールド= {ID、CatalogNumber、MOVIEID次のように(ファイルが正常にアップロードされた後)、テキストファイルからMemberMovieテーブルにデータをインポートするなど}

私の方法は次のとおりです。

  1. コンテキストを作成します。
  2. ファイル内の各行について、Actorテーブルでアーティストを参照します。
  3. Artistテーブルの各ムービーについて、一致するタイトルを検索します。
  4. 一致するMovieが見つかった場合は、コンテキストに新しいMemberMovieレコードを追加し、ctx.SaveChanges()を呼び出します。

私の実装のパフォーマンスはひどいです。私の期待は、これが数秒で(ファイルがアップロードされた後に)何千ものレコードで行えるということです。

私の質問はです:このようなバルク検索/挿入を実行する最適な方法は何ですか?新しく作成されたMemberMovieではなく、SaveChangesを一度呼び出す必要がありますか?ストアドプロシージャのようなものを使ってこれを実装する方が良いでしょうか?

私のループのスニペットは、おおよそこの(簡潔にするために編集)です:

while ((fline = file.ReadLine()) != null) 
{ 
    string [] token = fline.Split(separator); 

    string Actor = token[0]; 
    string Movie = token[1]; 
    string CatNumber = token[2]; 

    Actor found_actor = ctx.Actors.Where(a => a.Name.Equals(actor)).FirstOrDefault(); 

    if (found_actor == null) 
     continue; 

    Movie found_movie = found_actor.Movies.Where(s => s.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault(); 

    if (found_movie == null) 
     continue; 

    ctx.MemberMovies.AddObject(new MemberMovie() 
    { 
     MemberProfileID = profile_id, 
     CatalogNumber = CatNumber, 
     Movie = found_movie 
    }); 

    try 
    { 
     ctx.SaveChanges(); 
    } 
    catch 
    { 
    } 
} 

すべてのヘルプは歓迎です!

おかげで、デニス

+0

EFのこの種のタスクのパフォーマンスが低いです。 EFは一括操作をサポートしていないため、インポート、マイグレーションなどはすべて遅いです。最初にテーブルにインデックスを追加し、DBへのラウンドトリップ数を減らそうとします。たとえば、John Wayneと50のレコードがある場合、Actorテーブルと関連するすべてのMoviesを50回クエリします。アルゴリズムの再定義が必要になります。必要なすべてのアクターを一緒にロードすることもできます。処理時間は短縮されますが、実際の処理とメモリ負荷は増加します。 –

答えて

1

まず:それはある

When should I call SaveChanges() when creating 1000's of Entity Framework objects? (like during an import)

は、いくつかの時間前、私は1後のSaveChangesを呼び出すことについての答えを書いて、nまたは全て行実際にはSaveChangesを1行以上の呼び出しの後に呼び出すほうがいいですが、結局はそうではありません。第二に

あなたが作品で俳優のテーブルとタイトルに名前のインデックスを持っていることを確認し、それが役立つはずです。

の代わりに::

Actor found_actor = ctx.Actors.Where(a => a.Name.Equals(actor)).FirstOrDefault();

あなたが選択することができます。

int? found_actor_id = ctx.Actors.Where(a => a.Name.Equals(actor)).Select(a => a.ID).FirstOrDefault();

、その後

をまた、あなたが唯一の彼のIDが必要な場合は、全体の俳優を選ぶべきではありません

Something.ActorID = found_actor_id;

アクターエンティティ全体を必要とせず、特に索引と組み合わされたときに追加ルックアップを必要としないので、これはより高速になる可能性があります。

サード:

あなたは非常に大きなファイルを送信する場合、タイムアウトの可能性がさらに良好なパフォーマンスで、依然として存在しています。別のスレッドでこのインポートを実行し、すぐに応答を返す必要があります。すべてのインポートで何らかの識別子を与え、ユーザーがこのIDでステータスを確認できるようにすることができます。

+0

Lukasz - 詳細な回答をいただきありがとうございます。私は本当に時間を感謝し、またあなたの他の質問/回答へのリンクも本当に良い情報を持っていました。 –

関連する問題