2017-01-19 135 views
-1

Entity Framework 6.1.3経由でMS SQL Serverデータベースに約50.000行を挿入しようとしていますが、時間がかかりすぎます。私はthis answerに続いた。 AutoDetectChangesEnabledを無効にし、1000個のエンティティを追加した後にSaveChangesを呼び出します。それでも約7〜8分かかります。私はこれをリモートサーバーとローカルサーバーで試しました。それほど大きな違いはありません。私はこれが正常だとは思わない。何か忘れましたか?大量のデータでEntityFrameworkの挿入速度が非常に遅い

static void Main(string[] args) 
    { 

     var personCount = 50000; 
     var personList = new List<Person>(); 
     var random = new Random(); 

     for (int i = 0; i < personCount; i++) 
     { 
      personList.Add(new Person 
      { 
       CreateDate = DateTime.Now, 
       DateOfBirth = DateTime.Now, 
       FirstName = "Name", 
       IsActive = true, 
       IsDeleted = false, 
       LastName = "Surname", 
       PhoneNumber = "", 
       PlaceOfBirth = "Trabzon", 
       Value0 = random.NextDouble(), 
       Value1 = random.Next(), 
       Value10 = random.NextDouble(), 
       Value2 = random.Next(), 
       Value3 = random.Next(), 
       Value4 = random.Next(), 
       Value5 = random.Next(), 
       Value6 = "Value6", 
       Value7 = "Value7", 
       Value8 = "Value8", 
       Value9 = random.NextDouble() 
      }); 
     } 

     MyDbContext context = null; 

     try 
     { 
      context = new MyDbContext(); 
      context.Configuration.AutoDetectChangesEnabled = false; 

      int count = 0; 
      foreach (var entityToInsert in personList) 
      { 
       ++count; 
       context = AddToContext(context, entityToInsert, count, 1000, true); 
      } 

      context.SaveChanges(); 
     } 
     finally 
     { 
      if (context != null) 
       context.Dispose(); 
     } 

    } 

    private static MyDbContext AddToContext(MyDbContext context, Person entity, int count, int commitCount, bool recreateContext) 
    { 
     context.Set<Person>().Add(entity); 

     if (count % commitCount == 0) 
     { 
      context.SaveChanges(); 
      if (recreateContext) 
      { 
       context.Dispose(); 
       context = new MyDbContext(); 
       context.Configuration.AutoDetectChangesEnabled = false; 
      } 
     } 

     return context; 
    } 

Personクラス:プロファイラから追跡

public class Person 
{ 
    public int Id { get; set; } 

    [MaxLength(50)] 
    public string FirstName { get; set; } 

    [MaxLength(50)] 
    public string LastName { get; set; } 

    public DateTime DateOfBirth { get; set; } 

    [MaxLength(50)] 
    public string PlaceOfBirth { get; set; } 

    [MaxLength(15)] 
    public string PhoneNumber { get; set; } 

    public bool IsActive { get; set; } 

    public DateTime CreateDate { get; set; } 

    public int Value1 { get; set; } 

    public int Value2 { get; set; } 

    public int Value3 { get; set; } 

    public int Value4 { get; set; } 

    public int Value5 { get; set; } 

    [MaxLength(50)] 
    public string Value6 { get; set; } 

    [MaxLength(50)] 
    public string Value7 { get; set; } 

    [MaxLength(50)] 
    public string Value8 { get; set; } 

    public double Value9 { get; set; } 

    public double Value10 { get; set; } 

    public double Value0 { get; set; } 

    public bool IsDeleted { get; set; } 
} 

問合せ:

exec sp_executesql N'INSERT [dbo].[Person]([FirstName], [LastName],  [DateOfBirth], [PlaceOfBirth], [PhoneNumber], [IsActive], [CreateDate],  [Value1], [Value2], [Value3], [Value4], [Value5], [Value6], [Value7], [Value8],  [Value9], [Value10], [Value0], [IsDeleted]) 
VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16, @17, @18) 
SELECT [Id] 
FROM [dbo].[Person] 
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()',N'@0 nvarchar(50),@1  nvarchar(50),@2 datetime2(7),@3 nvarchar(50),@4 nvarchar(15),@5 bit,@6 datetime2(7),@7 int,@8 int,@9 int,@10 int,@11 int,@12 nvarchar(50),@13 nvarchar(50),@14 nvarchar(50),@15 float,@16 float,@17 float,@18 bit',@0=N'Name',@1=N'Surname',@2='2017-01-19 10:59:09.9882591',@3=N'Trabzon',@4=N'',@5=1,@6='2017-01-19 10:59:09.9882591',@7=731825903,@8=1869842619,@9=1701414555,@10=1468342767,@11=1962019787,@12=N'Value6',@13=N'Value7',@14=N'Value8',@15=0,65330243467041405,@16=0,85324223938083377,@17=0,7146566792925152,@18=0 

は私が唯一のEFでこれを解決したい

は、ここに私のコードです。今私にはたくさんの選択肢があります。しかし、他のチャンスがないと仮定することができます。

ここでの主な問題は、私が参照した答えと同じアプローチを使用したことです。 191秒で560000個のエンティティを挿入します。しかし、私は7分で50000を挿入することができます。

+1

あなたは '偽= context.Configuration.ValidateOnSaveEnabled;' しようとしましたか? –

+1

人の定義を教えてください。索引付けされた列が多数ある可能性がありますか? AddToContextメソッドが必要な理由それを削除してみてください。 – SirBirne

+0

ビッグインサートにはhttps://efbulkinsert.codeplex.com/などを使用することを検討してください。私が前にやったもう一つのことは、複数のコンテキストを開き、すべてを並行して挿入することでした。 – Mats391

答えて

4

AutoDetectChangesを無効にすると、既にChangeTrackerの問題が解消されています。

私は通常、これらのソリューションのを行うためにお勧めします

  1. AddRange上で複数のバッチで偽
  2. SPLITのSaveChangesへ(推奨)
  3. SETのAutoDetectChangesを追加

参照:http://entityframework.net/improve-ef-add-performance

複数のバッチを作成しても、AutoDectectChangesをすでにfalseに設定しているため、実際にパフォーマンスが向上したり低下することはありません。

重要な問題は、Entity Frameworkが、挿入する必要のあるエンティティごとにデータベースの往復を行うことです。したがって、50,000のエンティティを挿入すると、INSANEという50,000データベース往復が実行されます。

問題を解決するために必要なことは、データベースの往復回数を減らすことです。それを行うには

つの無料の方法は、SqlBulkCopyを使用しています:https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy(v=vs.110).aspx


免責事項:私はこのライブラリは、あなたがあなたのために必要なすべての一括操作を実行することができますEntity Framework Extensions

の持ち主ですシナリオ:

  • バルクSaveChanges
  • 一括挿入
  • バルク
  • 一括更新
  • バルク

あなたは数秒で50,000エンティティを挿入することができるようになりますマージ削除します。

// Easy to use 
context.BulkSaveChanges(); 

// Easy to customize 
context.BulkSaveChanges(bulk => bulk.BatchSize = 100); 

// Perform Bulk Operations 
context.BulkDelete(customers); 
context.BulkInsert(customers); 
context.BulkUpdate(customers); 

// Customize Primary Key 
context.BulkMerge(customers, operation => { 
    operation.ColumnPrimaryKeyExpression = 
     customer => customer.Code; 
}); 
+0

人々はどこにsql.data.sqlclientライブラリを見つけるか?いくつかのポストは、.NET Compact Frameworkのインストールを提案しています。これは、これはリモートデータベースではなくローカルデータベースに対してのみ機能しますか? – powerfade917

+0

こんにちは@ powerfade917、私はあなたの質問を理解することはできません。 –

+0

私はSqlBulkCopyがローカルではないデータベースで使用できるかどうか疑問に思っていました.netコンパクトなフレームワークは主にモバイル用またはタブレット用です。 – powerfade917

関連する問題