none
EntityFWのDbContext.SaveChanges() が遅すぎる RRS feed

  • 質問

  • Entity Framework4.3 コードファースト + SQL Server Compact 4.0で開発を行っています。

    大量のデータを DbContext の SaveChanges() メソッドで処理しようとした場合、

    かなりの時間が掛かってしまい、途方にくれています。

        public class Sample
        {
            public int Id { get; set; }
            public string Str { get; set; }
        }
    
        public class Context : DbContext
        {
            public DbSet<Sample> Samples { get; set; }
        }
            var context = new Context();
            context.Configuration.AutoDetectChangesEnabled = false;
    
            //10000~程度のアイテムを追加
            foreach (var item in manyItems)
            {
                context.Samples.Add(d);
            }
            context.SaveChanges();

    単純なサンプルですが、上記のサンプルで10万件のレコードを処理しようとすると、

    SaveChanges() で 30分もの時間が掛かっています。

    高速化するに当たり、何か指摘する点や情報をお持ちの方はいらっしゃいませんでしょうか?

    2012年2月22日 5:47

回答

  • Add()1つ1つがSQL文のINSERT文に変換されて実行されます。これはもうどうしようもないと思います。

    答えになっていないとは思いますが、Entity Frameworkを経由せず直接SQL Server Compactを操作してデータ追加をするとか。

    別質問で、10万件のINSERT文が遅いという質問に対しパラメタライズドクエリを使用することで高速化されると提案される方々がおられましたが、Entity Frameworkは既にパラメタライズドクエリを使用していますし…。(VB.NETでDB2の1回の接続で複数のINSERT文を発行したいのですが、お作法を教えてください。

    • 回答としてマーク 山本春海 2012年3月2日 8:39
    2012年2月22日 6:49
  • 最近の Entity Framework で改善がなされているかどうかまではわからないのですが、LinqToSQL と初期の Entity Framework において、INSERT 処理は、1レコード毎に INSERT 文を生成するようになっています。これは、Entity オブジェクトの全てのプロパティについて、省略可能性をチェックして INSERT 文の項目リストを生成しているためです。

    このため、10項目のレコードを持つ1万レコードを挿入しようとすると、1万個のエンティティオブジェクトに対して10項目すべて、合計10万項目の初期値チェックが実施されます。LinqToSQL や Entity Framework における挿入処理で大規模な時間がかかる場合は、これが原因の大半を占めると思います。

    LinqToSQL の場合は DataContext の OnInsert を override し、初期の Entity Framework では Function Mapping を用います。(http://msdn.microsoft.com/en-us/library/cc716711.aspx

    参考までに、LinqToSQL で30万行のINSERTが、3時間ぐらいかかるものが OnInsert に INSERT 文を記載することで5分程度になった実績があります。上記の処理は、純粋に LinqToSQL/EntityFramework 内部の文字列加工にかかる時間なので、ほとんどの場合に大きな効果があがります。


    2012年2月22日 9:35

すべての返信

  • Add()1つ1つがSQL文のINSERT文に変換されて実行されます。これはもうどうしようもないと思います。

    答えになっていないとは思いますが、Entity Frameworkを経由せず直接SQL Server Compactを操作してデータ追加をするとか。

    別質問で、10万件のINSERT文が遅いという質問に対しパラメタライズドクエリを使用することで高速化されると提案される方々がおられましたが、Entity Frameworkは既にパラメタライズドクエリを使用していますし…。(VB.NETでDB2の1回の接続で複数のINSERT文を発行したいのですが、お作法を教えてください。

    • 回答としてマーク 山本春海 2012年3月2日 8:39
    2012年2月22日 6:49
  • 最近の Entity Framework で改善がなされているかどうかまではわからないのですが、LinqToSQL と初期の Entity Framework において、INSERT 処理は、1レコード毎に INSERT 文を生成するようになっています。これは、Entity オブジェクトの全てのプロパティについて、省略可能性をチェックして INSERT 文の項目リストを生成しているためです。

    このため、10項目のレコードを持つ1万レコードを挿入しようとすると、1万個のエンティティオブジェクトに対して10項目すべて、合計10万項目の初期値チェックが実施されます。LinqToSQL や Entity Framework における挿入処理で大規模な時間がかかる場合は、これが原因の大半を占めると思います。

    LinqToSQL の場合は DataContext の OnInsert を override し、初期の Entity Framework では Function Mapping を用います。(http://msdn.microsoft.com/en-us/library/cc716711.aspx

    参考までに、LinqToSQL で30万行のINSERTが、3時間ぐらいかかるものが OnInsert に INSERT 文を記載することで5分程度になった実績があります。上記の処理は、純粋に LinqToSQL/EntityFramework 内部の文字列加工にかかる時間なので、ほとんどの場合に大きな効果があがります。


    2012年2月22日 9:35
  • こんにちは、Kinenow さん。

    フォーラムのご利用ありがとうございます。オペレーターの山本です。
    しばらく経ちましたが、みなさんからの情報は確認されましたか?

    参考になる情報をいただいているかと思われましたので、勝手ながら私のほうで回答としてマークさせていただきました。
    情報くださったみなさん、ありがとうございます。

    いただいた情報の中で解決に役立った投稿や、参考になる情報など有効な情報には回答としてマークすることをお願いしています。
    今後、同じ問題でこのスレッドを参照される方にも、有効な情報を活用いただけるかと思いますので、ご協力よろしくお願いいたします。

    今後とも、MSDN フォーラムをよろしくお願いいたします。
    _____________________
    日本マイクロソフト株式会社 フォーラム オペレーター 山本 春海

    2012年3月2日 8:39