5

EF Code First を使用して約 2500 行を挿入する必要があります。

私の元のコードは次のようになりました。

foreach(var item in listOfItemsToBeAdded)
{
    //biz logic
    context.MyStuff.Add(i);
}

これには非常に長い時間がかかりました。1 回の通話にかかる時間は約 2.2 秒で、DBSet.Add()約 90 分に相当します。

コードを次のようにリファクタリングしました。

var tempItemList = new List<MyStuff>();
foreach(var item in listOfItemsToBeAdded)
{
    //biz logic
    tempItemList.Add(item)
}
context.MyStuff.ToList().AddRange(tempItemList);

これは、実行に約 4 秒しかかかりません。ただし、.ToList()現在テーブルにあるすべてのアイテムをクエリします。これは非常に必要であり、長期的には危険であり、さらに時間がかかる可能性があります。1つの回避策はcontext.MyStuff.Where(x=>x.ID = *empty guid*).AddRange(tempItemList)、何も返されないことがわかっているため、次のようにすることです。

しかし、EF Code First を使用して一括挿入する効率的な方法を他の誰かが知っているかどうか、私は興味がありますか?

4

9 に答える 9

13

検証は通常、EF の非常に高価な部分です。次のように無効にすることで、パフォーマンスが大幅に向上しました。

context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;

同様のSOの質問でそれを見つけたと思います-おそらくそれはこの答えでした

その質問に対する別の回答は、一括挿入のパフォーマンスが本当に必要な場合は、を使用することを検討する必要があることを正しく指摘していますSystem.Data.SqlClient.SqlBulkCopy。この問題で EF と ADO.NET のどちらを選択するかは、実際には優先順位に基づいています。

于 2013-09-03T20:46:24.627 に答える
2

私はクレイジーな考えを持っていますが、それはあなたを助けると思います.

100 個の項目を追加するたびに、SaveChanges を呼び出します。EF の Track Changes は、膨大なデータでパフォーマンスが非常に悪いと感じています。

于 2013-09-03T20:33:50.307 に答える
2

EF を使用して一括挿入を行う方法については、この記事をお勧めします。

Entity Framework と遅いバルク INSERT

彼はこれらの領域を調査し、パフォーマンスを比較します。

  1. デフォルトの EF (30,000 レコードの追加を完了するのに 57 分)
  2. ADO.NET コードに置き換える (同じ 30,000 で25秒)
  3. コンテキストの肥大化 - 作業単位ごとに新しいコンテキストを使用して、アクティブなコンテキスト グラフを小さく保ちます (同じ 30,000 の挿入に 33 秒かかります)。
  4. 大きなリスト - AutoDetectChangesEnabled をオフにします (時間を約 20 秒に短縮します)
  5. バッチ処理 (16 秒まで)
  6. DbTable.AddRange() - (パフォーマンスは 12 の範囲にあります)
于 2014-06-20T03:04:50.923 に答える
0
    public static void BulkInsert(IList list, string tableName)
    {
        var conn = (SqlConnection)Db.Connection;
        if (conn.State != ConnectionState.Open) conn.Open();

        using (var bulkCopy = new SqlBulkCopy(conn))
        {
            bulkCopy.BatchSize = list.Count;
            bulkCopy.DestinationTableName = tableName;

            var table = ListToDataTable(list);
            bulkCopy.WriteToServer(table);
        }
    }

    public static DataTable ListToDataTable(IList list)
    {
        var dt = new DataTable();
        if (list.Count <= 0) return dt;

        var properties = list[0].GetType().GetProperties();
        foreach (var pi in properties)
        {
            dt.Columns.Add(pi.Name, Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType);
        }

        foreach (var item in list)
        {
            DataRow row = dt.NewRow();
            properties.ToList().ForEach(p => row[p.Name] = p.GetValue(item, null) ?? DBNull.Value);
            dt.Rows.Add(row);
        }
        return dt;
    }
于 2017-01-06T03:42:25.150 に答える