복붙노트

[SQL] 엔티티 프레임 워크에 삽입하는 가장 빠른 방법

SQL

엔티티 프레임 워크에 삽입하는 가장 빠른 방법

내가 엔티티 프레임 워크에 삽입하는 가장 빠른 방법을 찾고 있어요.

당신이 활성 TransactionScope에이 어디 때문에 시나리오의이 부탁 해요과 삽입 (4000) 거대하다. 그것은 잠재적으로 마지막으로 더 십분 (거래의 기본 시간 초과)에 비해, 이것은 불완전한 거래로 이어질 것입니다 수 있습니다.

해결법

  1. ==============================

    1.귀하의 질문에 대한 코멘트에주의로 :

    귀하의 질문에 대한 코멘트에주의로 :

    그게 당신이 할 수있는 최악의 일이다! 매우 아래 각 레코드 감속 대량 삽입에 대한 SaveChanges를 ()를 호출. 나는 매우 가능성이 성능이 향상됩니다 몇 가지 간단한 테스트를 할 것이다 :

    벌크 삽입을 위해 나는 일하고 이런 패턴을 실험 :

    using (TransactionScope scope = new TransactionScope())
    {
        MyDbContext context = null;
        try
        {
            context = new MyDbContext();
            context.Configuration.AutoDetectChangesEnabled = false;
    
            int count = 0;            
            foreach (var entityToInsert in someCollectionOfEntitiesToInsert)
            {
                ++count;
                context = AddToContext(context, entityToInsert, count, 100, true);
            }
    
            context.SaveChanges();
        }
        finally
        {
            if (context != null)
                context.Dispose();
        }
    
        scope.Complete();
    }
    
    private MyDbContext AddToContext(MyDbContext context,
        Entity entity, int count, int commitCount, bool recreateContext)
    {
        context.Set<Entity>().Add(entity);
    
        if (count % commitCount == 0)
        {
            context.SaveChanges();
            if (recreateContext)
            {
                context.Dispose();
                context = new MyDbContext();
                context.Configuration.AutoDetectChangesEnabled = false;
            }
        }
    
        return context;
    }
    

    나는 DB에 560.000 엔티티 (9 스칼라 속성, 아니 탐색 속성)을 삽입하는 테스트 프로그램이 있습니다. 이 코드는 3 분 미만에서 작동합니다.

    성능을 위해 (100 또는 1000 주위에 "다") "다"기록 후 () SaveChanges를 호출하는 것이 중요하다. 또한 SaveChanges를 한 후 컨텍스트를 처분하고 새를 만들 수있는 성능을 향상시킵니다. 이 모든 entites에서 컨텍스트를 삭제, SaveChanges를 그렇게하지 않고, 실체는 여전히 변경되지 않은 상태에서 상황에 첨부됩니다. 이 단계에 의해 삽입 단계 속도가 느려집니다 어떤 맥락에서 연결 실체의 증가 크기입니다. 그래서, 잠시 후을 취소하는 것이 도움이된다.

    여기 제 560000 개 기관에 대한 몇 가지 측정은 다음과 같습니다 :

    첫 번째 시험에서의 동작은 상기 성능이 매우 비선형 적이며 매우 시간이 지남에 따라 감소한다는 것이다. ( "많은 시간"나는 20 분 50.000 기관에서 중지, 나는이 테스트를 완료 결코 추정이다.)이 비선형 행동이 다른 모든 테스트에서 그렇게 중요하지 않습니다.

  2. ==============================

    2.충분히 잘 조합의 증가 속도.

    충분히 잘 조합의 증가 속도.

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

    3.가장 빠른 방법은 내가 개발 한 대량 삽입 확장자를 사용하는 것

    가장 빠른 방법은 내가 개발 한 대량 삽입 확장자를 사용하는 것

    참고 :이 무료하지 상용 제품입니다

    그것은 최대 성능을 얻을 수 SqlBulkCopy의 및 사용자 정의 DataReader를 사용합니다. 그 결과는 20 배 빠른 정기적으로 삽입 또는 AddRange를 사용하는 것보다

    사용법은 매우 간단

    context.BulkInsert(hugeAmountOfEntities);
    
  4. ==============================

    4.당신은이에 대한 System.Data.SqlClient.SqlBulkCopy를 사용하여보고해야한다. 여기에 문서, 그리고 물론 자습서의 많은 온라인이 있습니다.

    당신은이에 대한 System.Data.SqlClient.SqlBulkCopy를 사용하여보고해야한다. 여기에 문서, 그리고 물론 자습서의 많은 온라인이 있습니다.

    죄송합니다, 나는 당신이 EF 당신이 원하는 것을 얻을 수있는 간단한 대답을 찾고 알고 있지만, 일괄 작업으로 ORMs이 의미하는 무엇을 정말하지 않습니다.

  5. ==============================

    5.나는 아담 Rackis에 동의합니다. SqlBulkCopy의 다른 하나의 데이터 소스에서 대량의 기록을 전송하는 가장 빠른 방법입니다. 나는 20K 기록을 복사하려면이 옵션을 사용하고는 3 초 미만했다. 아래의 예를 보라.

    나는 아담 Rackis에 동의합니다. SqlBulkCopy의 다른 하나의 데이터 소스에서 대량의 기록을 전송하는 가장 빠른 방법입니다. 나는 20K 기록을 복사하려면이 옵션을 사용하고는 3 초 미만했다. 아래의 예를 보라.

    public static void InsertIntoMembers(DataTable dataTable)
    {           
        using (var connection = new SqlConnection(@"data source=;persist security info=True;user id=;password=;initial catalog=;MultipleActiveResultSets=True;App=EntityFramework"))
        {
            SqlTransaction transaction = null;
            connection.Open();
            try
            {
                transaction = connection.BeginTransaction();
                using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
                {
                    sqlBulkCopy.DestinationTableName = "Members";
                    sqlBulkCopy.ColumnMappings.Add("Firstname", "Firstname");
                    sqlBulkCopy.ColumnMappings.Add("Lastname", "Lastname");
                    sqlBulkCopy.ColumnMappings.Add("DOB", "DOB");
                    sqlBulkCopy.ColumnMappings.Add("Gender", "Gender");
                    sqlBulkCopy.ColumnMappings.Add("Email", "Email");
    
                    sqlBulkCopy.ColumnMappings.Add("Address1", "Address1");
                    sqlBulkCopy.ColumnMappings.Add("Address2", "Address2");
                    sqlBulkCopy.ColumnMappings.Add("Address3", "Address3");
                    sqlBulkCopy.ColumnMappings.Add("Address4", "Address4");
                    sqlBulkCopy.ColumnMappings.Add("Postcode", "Postcode");
    
                    sqlBulkCopy.ColumnMappings.Add("MobileNumber", "MobileNumber");
                    sqlBulkCopy.ColumnMappings.Add("TelephoneNumber", "TelephoneNumber");
    
                    sqlBulkCopy.ColumnMappings.Add("Deleted", "Deleted");
    
                    sqlBulkCopy.WriteToServer(dataTable);
                }
                transaction.Commit();
            }
            catch (Exception)
            {
                transaction.Rollback();
            }
    
        }
    }
    
  6. ==============================

    6.나는 EF를 사용하여 대량 삽입 작업을 수행하는 방법에 대한이 기사를 추천 할 것입니다.

    나는 EF를 사용하여 대량 삽입 작업을 수행하는 방법에 대한이 기사를 추천 할 것입니다.

    엔티티 프레임 워크와 느린 대량 INSERT들

    그는이 지역을 살펴보고 성능을 비교 :

  7. ==============================

    7.나는 (굉장 아이디어 남자 주셔서 감사합니다) Slauma의 답변을 조사했습니다, 그리고 최적의 속도를 칠 때까지 나는 배치 크기를 감소했습니다. Slauma의 결과를 보면 :

    나는 (굉장 아이디어 남자 주셔서 감사합니다) Slauma의 답변을 조사했습니다, 그리고 최적의 속도를 칠 때까지 나는 배치 크기를 감소했습니다. Slauma의 결과를 보면 :

    1 내지 10의 이동시의 속도 증가가 있다는 것을 볼 수 있으며, 10 내지 100 만, 100 내지 1000의 삽입 속도가 다시 떨어지고있다.

    내가 여기에 10에서 100 사이의 값 어딘가에 배치 크기를 줄일 때, 그리고 무슨 일이 일어나고 있는지에 초점을했습니다 그래서 내 결과 (내 시간이 서로 다른 가치가 있도록, 다른 행의 내용을 사용하고 있습니다)입니다 :

    Quantity    | Batch size    | Interval
    1000    1   3
    10000   1   34
    100000  1   368
    
    1000    5   1
    10000   5   12
    100000  5   133
    
    1000    10  1
    10000   10  11
    100000  10  101
    
    1000    20  1
    10000   20  9
    100000  20  92
    
    1000    27  0
    10000   27  9
    100000  27  92
    
    1000    30  0
    10000   30  9
    100000  30  92
    
    1000    35  1
    10000   35  9
    100000  35  94
    
    1000    50  1
    10000   50  10
    100000  50  106
    
    1000    100 1
    10000   100 14
    100000  100 141
    

    내 결과를 바탕으로, 실제 최적 배치 크기 (30)의 주변 값입니다. 그것은 모두 10과 100 문제는, 내가 30 최적 왜 아무 생각이 없으며, 내가 그것을 위해 어떤 논리적 인 설명을 볼 수 있었던 것보다 적은이다.

  8. ==============================

    8.다른 사람이 말했듯이 SqlBulkCopy의 당신이 정말 좋은 삽입 성능을 원하는 경우에 할 수있는 방법입니다.

    다른 사람이 말했듯이 SqlBulkCopy의 당신이 정말 좋은 삽입 성능을 원하는 경우에 할 수있는 방법입니다.

    그것은 구현하는 비트 성가신하지만 당신을 도울 수있는 라이브러리가있다. 이 몇 밖으로있다 그러나 나는 내 자신의 라이브러리 이번에 shamelesslyplug됩니다 https://github.com/MikaelEliasson/EntityFramework.Utilities#batch-insert-entities

    당신이 필요로 할 유일한 코드는 다음과 같습니다

     using (var db = new YourDbContext())
     {
         EFBatchOperation.For(db, db.BlogPosts).InsertAll(list);
     }
    

    그래서 얼마나 빨리 무엇입니까? 너무 많은 요인, 컴퓨터 성능, 네트워크 등 내가 만든 한 성능 테스트는 당신이처럼 EF 구성을 최적화 할 경우 25000 개체가 10 초 주위에서 로컬 호스트의 표준 방법을 삽입 할 수 있습니다 제안 객체의 크기 등에 의존하기 때문에 말을 아주 열심히 다른 답변에서 언급했다. 이 300ms 정도 걸립니다 EFUtilities으로. 더욱 흥미로운 내가 초당 200K 기관 평균,이 방법을 사용하여 15초에서 3 백만 개체 주위에 저장 한 것입니다.

    한 가지 문제는 releated 데이터를 삽입해야하는 경우 당연히이다. 이것은 위의 방법을 사용하여 SQL 서버에과 효과적으로 수행하지만 당신은 외래 키를 설정할 수 있도록 부모에 대한 ID의 응용 프로그램 코드에서 발생하게하는 ID 세대 전략을 가지고 당신을 필요로 할 수있다. 이것은 GUID를 또는 힐로 ID 생성 같은 것을 사용하여 수행 할 수 있습니다.

  9. ==============================

    9.이 여기에 언급되지 않았다 나는 여기 recomment의 EFCore.BulkExtensions 원하는

    이 여기에 언급되지 않았다 나는 여기 recomment의 EFCore.BulkExtensions 원하는

    context.BulkInsert(entitiesList);                 context.BulkInsertAsync(entitiesList);
    context.BulkUpdate(entitiesList);                 context.BulkUpdateAsync(entitiesList);
    context.BulkDelete(entitiesList);                 context.BulkDeleteAsync(entitiesList);
    context.BulkInsertOrUpdate(entitiesList);         context.BulkInsertOrUpdateAsync(entitiesList);         // Upsert
    context.BulkInsertOrUpdateOrDelete(entitiesList); context.BulkInsertOrUpdateOrDeleteAsync(entitiesList); // Sync
    context.BulkRead(entitiesList);                   context.BulkReadAsync(entitiesList);
    
  10. ==============================

    10.당신이 추가 엔티티 () 맥락에서 다른 사전로드 된 엔티티 (예를 들어, 탐색 속성)에 의존하는 경우 폐기 () 문맥은 문제를 야기

    당신이 추가 엔티티 () 맥락에서 다른 사전로드 된 엔티티 (예를 들어, 탐색 속성)에 의존하는 경우 폐기 () 문맥은 문제를 야기

    나는 동일한 성능을 달성하기 위해 작은 내 컨텍스트를 유지하기 위해 유사한 개념을 사용

    하지만 그 대신 폐기 () 컨텍스트 및 재 작성, 나는 단지) ​​(엔티티 이미 SaveChanges를 분리

    public void AddAndSave<TEntity>(List<TEntity> entities) where TEntity : class {
    
    const int CommitCount = 1000; //set your own best performance number here
    int currentCount = 0;
    
    while (currentCount < entities.Count())
    {
        //make sure it don't commit more than the entities you have
        int commitCount = CommitCount;
        if ((entities.Count - currentCount) < commitCount)
            commitCount = entities.Count - currentCount;
    
        //e.g. Add entities [ i = 0 to 999, 1000 to 1999, ... , n to n+999... ] to conext
        for (int i = currentCount; i < (currentCount + commitCount); i++)        
            _context.Entry(entities[i]).State = System.Data.EntityState.Added;
            //same as calling _context.Set<TEntity>().Add(entities[i]);       
    
        //commit entities[n to n+999] to database
        _context.SaveChanges();
    
        //detach all entities in the context that committed to database
        //so it won't overload the context
        for (int i = currentCount; i < (currentCount + commitCount); i++)
            _context.Entry(entities[i]).State = System.Data.EntityState.Detached;
    
        currentCount += commitCount;
    } }
    

    시도 캐치하고 필요한 경우 TransactionScope에 ()로 포장, 코드 청결을 유지하기 위해 여기에 표시되지

  11. ==============================

    11.나는 이것이 아주 오래된 질문 알지만, 사람 여기 하나는 EF와 함께 사용하여 대량 삽입에 대한 확장 방법을 개발, 그리고 체크 할 때, 나는 도서관 (한 개발자)는 오늘 $ 599 비용이 있다는 것을 발견했다. 이 너무 많이 삽입 어쩌면 그것은 단지 대부분을위한 그러나 전체 라이브러리에 대한 의미가 있습니다.

    나는 이것이 아주 오래된 질문 알지만, 사람 여기 하나는 EF와 함께 사용하여 대량 삽입에 대한 확장 방법을 개발, 그리고 체크 할 때, 나는 도서관 (한 개발자)는 오늘 $ 599 비용이 있다는 것을 발견했다. 이 너무 많이 삽입 어쩌면 그것은 단지 대부분을위한 그러나 전체 라이브러리에 대한 의미가 있습니다.

    여기에 내가 만든 아주 간단한 확장 방법이다. 내가 먼저 데이터베이스 쌍 (첫 번째 코드 테스트하지 않지만, 나는 그것이 동일하게 작동합니다 생각하는) 것을 사용합니다. 당신의 컨텍스트의 이름으로 변경 YourEntities :

    public partial class YourEntities : DbContext
    {
        public async Task BulkInsertAllAsync<T>(IEnumerable<T> entities)
        {
            using (var conn = new SqlConnection(Database.Connection.ConnectionString))
            {
                await conn.OpenAsync();
    
                Type t = typeof(T);
    
                var bulkCopy = new SqlBulkCopy(conn)
                {
                    DestinationTableName = GetTableName(t)
                };
    
                var table = new DataTable();
    
                var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));
    
                foreach (var property in properties)
                {
                    Type propertyType = property.PropertyType;
                    if (propertyType.IsGenericType &&
                        propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        propertyType = Nullable.GetUnderlyingType(propertyType);
                    }
    
                    table.Columns.Add(new DataColumn(property.Name, propertyType));
                }
    
                foreach (var entity in entities)
                {
                    table.Rows.Add(
                        properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray());
                }
    
                bulkCopy.BulkCopyTimeout = 0;
                await bulkCopy.WriteToServerAsync(table);
            }
        }
    
        public void BulkInsertAll<T>(IEnumerable<T> entities)
        {
            using (var conn = new SqlConnection(Database.Connection.ConnectionString))
            {
                conn.Open();
    
                Type t = typeof(T);
    
                var bulkCopy = new SqlBulkCopy(conn)
                {
                    DestinationTableName = GetTableName(t)
                };
    
                var table = new DataTable();
    
                var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));
    
                foreach (var property in properties)
                {
                    Type propertyType = property.PropertyType;
                    if (propertyType.IsGenericType &&
                        propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        propertyType = Nullable.GetUnderlyingType(propertyType);
                    }
    
                    table.Columns.Add(new DataColumn(property.Name, propertyType));
                }
    
                foreach (var entity in entities)
                {
                    table.Rows.Add(
                        properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray());
                }
    
                bulkCopy.BulkCopyTimeout = 0;
                bulkCopy.WriteToServer(table);
            }
        }
    
        public string GetTableName(Type type)
        {
            var metadata = ((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace;
            var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace));
    
            var entityType = metadata
                    .GetItems<EntityType>(DataSpace.OSpace)
                    .Single(e => objectItemCollection.GetClrType(e) == type);
    
            var entitySet = metadata
                .GetItems<EntityContainer>(DataSpace.CSpace)
                .Single()
                .EntitySets
                .Single(s => s.ElementType.Name == entityType.Name);
    
            var mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
                    .Single()
                    .EntitySetMappings
                    .Single(s => s.EntitySet == entitySet);
    
            var table = mapping
                .EntityTypeMappings.Single()
                .Fragments.Single()
                .StoreEntitySet;
    
            return (string)table.MetadataProperties["Table"].Value ?? table.Name;
        }
    }
    

    당신은 그렇게,는 IEnumerable에서 모든 모음에 대해 그 상속을 그것을 사용할 수 있습니다 :

    await context.BulkInsertAllAsync(items);
    
  12. ==============================

    12.삽입하려는 데이터의 XML을 얻을 것이다 저장 프로 시저를 사용하려고합니다.

    삽입하려는 데이터의 XML을 얻을 것이다 저장 프로 시저를 사용하려고합니다.

  13. ==============================

    13.나는 @Slauma의 예를 들어 위의 일반적인 확장을 만들었습니다;

    나는 @Slauma의 예를 들어 위의 일반적인 확장을 만들었습니다;

    public static class DataExtensions
    {
        public static DbContext AddToContext<T>(this DbContext context, object entity, int count, int commitCount, bool recreateContext, Func<DbContext> contextCreator)
        {
            context.Set(typeof(T)).Add((T)entity);
    
            if (count % commitCount == 0)
            {
                context.SaveChanges();
                if (recreateContext)
                {
                    context.Dispose();
                    context = contextCreator.Invoke();
                    context.Configuration.AutoDetectChangesEnabled = false;
                }
            }
            return context;
        }
    }
    

    용법:

    public void AddEntities(List<YourEntity> entities)
    {
        using (var transactionScope = new TransactionScope())
        {
            DbContext context = new YourContext();
            int count = 0;
            foreach (var entity in entities)
            {
                ++count;
                context = context.AddToContext<TenancyNote>(entity, count, 100, true,
                    () => new YourContext());
            }
            context.SaveChanges();
            transactionScope.Complete();
        }
    }
    
  14. ==============================

    14.가능한 삽입 대량을 지원하는 일부 타사 라이브러리가 있습니다 :

    가능한 삽입 대량을 지원하는 일부 타사 라이브러리가 있습니다 :

    참조 : 엔티티 프레임 워크의 대량 삽입 라이브러리

    대량 삽입 라이브러리를 선택할 때,주의해야합니다. 만 엔티티 프레임 워크 확장 협회와 상속의 모든 종류를 지원하며 계속 지원하는 유일한 하나입니다.

    면책 조항 : 나는 엔티티 프레임 워크 확장의 소유자 해요

    이 라이브러리는 당신이 당신의 시나리오에 필요한 모든 대량 작업을 수행 할 수 있습니다 :

    // 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;
    });
    
  15. ==============================

    15.목록을 저장하는 가장 빠른 방법 중 하나 다음 코드를 적용해야합니다

    목록을 저장하는 가장 빠른 방법 중 하나 다음 코드를 적용해야합니다

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

    AutoDetectChangesEnabled = 거짓

    추가, AddRange 및 SaveChanges를이 : 변화를 감지하지 않습니다.

    ValidateOnSaveEnabled 거짓 =;

    변경 추적기를 감지하지 않습니다

    당신은 덩어리를 추가해야합니다

    Install-Package Z.EntityFramework.Extensions
    

    이제 다음과 같은 코드를 사용할 수 있습니다

    var context = new MyContext();
    
    context.Configuration.AutoDetectChangesEnabled = false;
    context.Configuration.ValidateOnSaveEnabled = false;
    
    context.BulkInsert(list);
    context.BulkSaveChanges();
    
  16. ==============================

    16.다음은 엔티티 프레임 워크를 사용하여 실제적인 예에 ​​SqlBulkCopy의 클래스를 사용 사이의 성능 비교가 어떻게 SQL Server 데이터베이스에 복잡한 객체 삽입 대량으로

    다음은 엔티티 프레임 워크를 사용하여 실제적인 예에 ​​SqlBulkCopy의 클래스를 사용 사이의 성능 비교가 어떻게 SQL Server 데이터베이스에 복잡한 객체 삽입 대량으로

    다른 사람이 이미 강조로,으로 ORMs은 대량 작업에 사용되는 것은 아니다. 그들은 유연성, 문제 및 기타 혜택 만 (대량 독서 제외) 대량 작업의 분리를 제공하고 그 중 하나를하지 않습니다.

  17. ==============================

    17.또 다른 옵션은 Nuget에서 사용할 수 SqlBulkTools을 사용하는 것입니다. 그것은 아주 사용하기 쉬운 몇 가지 강력한 기능을 가지고 있습니다.

    또 다른 옵션은 Nuget에서 사용할 수 SqlBulkTools을 사용하는 것입니다. 그것은 아주 사용하기 쉬운 몇 가지 강력한 기능을 가지고 있습니다.

    예:

    var bulk = new BulkOperations();
    var books = GetBooks();
    
    using (TransactionScope trans = new TransactionScope())
    {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager
        .ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
        {
            bulk.Setup<Book>()
                .ForCollection(books)
                .WithTable("Books") 
                .AddAllColumns()
                .BulkInsert()
                .Commit(conn);
        }
    
        trans.Complete();
    }
    

    더 많은 예제 및 고급 사용 설명서를 참조하십시오. 면책 조항 :이 라이브러리의 저자 및 전망을 내 자신의 의견이다.

  18. ==============================

    18.사용 SqlBulkCopy의 :

    사용 SqlBulkCopy의 :

    void BulkInsert(GpsReceiverTrack[] gpsReceiverTracks)
    {
        if (gpsReceiverTracks == null)
        {
            throw new ArgumentNullException(nameof(gpsReceiverTracks));
        }
    
        DataTable dataTable = new DataTable("GpsReceiverTracks");
        dataTable.Columns.Add("ID", typeof(int));
        dataTable.Columns.Add("DownloadedTrackID", typeof(int));
        dataTable.Columns.Add("Time", typeof(TimeSpan));
        dataTable.Columns.Add("Latitude", typeof(double));
        dataTable.Columns.Add("Longitude", typeof(double));
        dataTable.Columns.Add("Altitude", typeof(double));
    
        for (int i = 0; i < gpsReceiverTracks.Length; i++)
        {
            dataTable.Rows.Add
            (
                new object[]
                {
                        gpsReceiverTracks[i].ID,
                        gpsReceiverTracks[i].DownloadedTrackID,
                        gpsReceiverTracks[i].Time,
                        gpsReceiverTracks[i].Latitude,
                        gpsReceiverTracks[i].Longitude,
                        gpsReceiverTracks[i].Altitude
                }
            );
        }
    
        string connectionString = (new TeamTrackerEntities()).Database.Connection.ConnectionString;
        using (var connection = new SqlConnection(connectionString))
        {
            connection.Open();
            using (var transaction = connection.BeginTransaction())
            {
                using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
                {
                    sqlBulkCopy.DestinationTableName = dataTable.TableName;
                    foreach (DataColumn column in dataTable.Columns)
                    {
                        sqlBulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
                    }
    
                    sqlBulkCopy.WriteToServer(dataTable);
                }
                transaction.Commit();
            }
        }
    
        return;
    }
    
  19. ==============================

    19.SqlBulkCopy의 슈퍼 빠른

    SqlBulkCopy의 슈퍼 빠른

    이것은 내 구현 한 것입니다 :

    // at some point in my calling code, I will call:
    var myDataTable = CreateMyDataTable();
    myDataTable.Rows.Add(Guid.NewGuid,tableHeaderId,theName,theValue); // e.g. - need this call for each row to insert
    
    var efConnectionString = ConfigurationManager.ConnectionStrings["MyWebConfigEfConnection"].ConnectionString;
    var efConnectionStringBuilder = new EntityConnectionStringBuilder(efConnectionString);
    var connectionString = efConnectionStringBuilder.ProviderConnectionString;
    BulkInsert(connectionString, myDataTable);
    
    private DataTable CreateMyDataTable()
    {
        var myDataTable = new DataTable { TableName = "MyTable"};
    // this table has an identity column - don't need to specify that
        myDataTable.Columns.Add("MyTableRecordGuid", typeof(Guid));
        myDataTable.Columns.Add("MyTableHeaderId", typeof(int));
        myDataTable.Columns.Add("ColumnName", typeof(string));
        myDataTable.Columns.Add("ColumnValue", typeof(string));
        return myDataTable;
    }
    
    private void BulkInsert(string connectionString, DataTable dataTable)
    {
        using (var connection = new SqlConnection(connectionString))
        {
            connection.Open();
            SqlTransaction transaction = null;
            try
            {
                transaction = connection.BeginTransaction();
    
                using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
                {
                    sqlBulkCopy.DestinationTableName = dataTable.TableName;
                    foreach (DataColumn column in dataTable.Columns) {
                        sqlBulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
                    }
    
                    sqlBulkCopy.WriteToServer(dataTable);
                }
                transaction.Commit();
            }
            catch (Exception)
            {
                transaction?.Rollback();
                throw;
            }
        }
    }
    
  20. ==============================

    20.내 지식에 따라 거대한 삽입의 성능을 향상하는 엔티티 프레임 워크에는 대량 삽입이 없습니다.

    내 지식에 따라 거대한 삽입의 성능을 향상하는 엔티티 프레임 워크에는 대량 삽입이 없습니다.

    이 시나리오에서는 당신은 당신의 문제를 해결하기 위해 ADO.net에 SqlBulkCopy의로 갈 수있다

  21. ==============================

    21.혹시 백그라운드 작업자 또는 작업을 통해 삽입하는 시도 해 봤나?

    혹시 백그라운드 작업자 또는 작업을 통해 삽입하는 시도 해 봤나?

    제 경우 임 (NavigationProperties 의해) 외래 키 관계와 다른 테이블 (182)에 분배 7760 개 레지스터 삽입.

    작업이 없다면, 그것은 2 분 반을했다. 태스크 (Task.Factory.StartNew (...)) 내에서, 15 초 걸렸습니다.

    임은 컨텍스트에있는 모든 개체를 추가 한 후 SaveChanges를 ()를하고. (데이터 무결성을 보장하기 위해)

  22. ==============================

    22.당신이 SaveChanges를 ()를 수행 할 때, INSERT 문이 엔터티가 작동하는 방법 하나의 데이터베이스 하나에 전송되기 때문에 여기에 기록 된 모든 솔루션은 도움이되지 않습니다.

    당신이 SaveChanges를 ()를 수행 할 때, INSERT 문이 엔터티가 작동하는 방법 하나의 데이터베이스 하나에 전송되기 때문에 여기에 기록 된 모든 솔루션은 도움이되지 않습니다.

    데이터베이스와 다시 여행이 예를 들어 50 밀리의 경우 다음 삽입을 위해 필요한 시간은 레코드 수는 50 밀리 X입니다.

    당신은 BulkInsert을 사용해야합니다, 여기에 링크입니다 : https://efbulkinsert.codeplex.com/

    나는 그것을 사용하여 10-12초 5-6 분 감소 삽입 시간을 얻었다.

  23. ==============================

    23.당신은 대량 패키지 라이브러리를 사용할 수 있습니다. 1.0.0 버전 삽입 대량는 엔티티 프레임 워크> = 6.0.0을 가진 프로젝트에 사용된다.

    당신은 대량 패키지 라이브러리를 사용할 수 있습니다. 1.0.0 버전 삽입 대량는 엔티티 프레임 워크> = 6.0.0을 가진 프로젝트에 사용된다.

    자세한 설명은 여기 - 찾을 수 있습니다 Bulkoperation 소스 코드

  24. ==============================

    24.[NEW SOLUTION FOR POSTGRESQL] 이봐, 난 꽤 이전 게시물 알고 있지만, 나는 최근에 비슷한 문제로 실행 한, 그러나 우리는 PostgreSQL을 사용하고 있던. 나는 꽤 어려운 것으로 밝혀졌다 무슨 효과 bulkinsert를 사용하고 싶었다. 나는이 DB에 그렇게 할 수있는 적절한 무료 라이브러리를 발견하지 않았습니다. 나는 단지이 도우미를 발견했습니다 : https://bytefish.de/blog/postgresql_bulk_insert/ 이는 Nuget에 있습니다. 나는 자동 등록을하는 방식 엔티티 프레임 워크를 매핑 작은 매퍼를 작성했습니다 :

    [NEW SOLUTION FOR POSTGRESQL] 이봐, 난 꽤 이전 게시물 알고 있지만, 나는 최근에 비슷한 문제로 실행 한, 그러나 우리는 PostgreSQL을 사용하고 있던. 나는 꽤 어려운 것으로 밝혀졌다 무슨 효과 bulkinsert를 사용하고 싶었다. 나는이 DB에 그렇게 할 수있는 적절한 무료 라이브러리를 발견하지 않았습니다. 나는 단지이 도우미를 발견했습니다 : https://bytefish.de/blog/postgresql_bulk_insert/ 이는 Nuget에 있습니다. 나는 자동 등록을하는 방식 엔티티 프레임 워크를 매핑 작은 매퍼를 작성했습니다 :

    public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName)
            {
                var helper = new PostgreSQLCopyHelper<T>("dbo", "\"" + tableName + "\"");
                var properties = typeof(T).GetProperties();
                foreach(var prop in properties)
                {
                    var type = prop.PropertyType;
                    if (Attribute.IsDefined(prop, typeof(KeyAttribute)) || Attribute.IsDefined(prop, typeof(ForeignKeyAttribute)))
                        continue;
                    switch (type)
                    {
                        case Type intType when intType == typeof(int) || intType == typeof(int?):
                            {
                                helper = helper.MapInteger("\"" + prop.Name + "\"",  x => (int?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                                break;
                            }
                        case Type stringType when stringType == typeof(string):
                            {
                                helper = helper.MapText("\"" + prop.Name + "\"", x => (string)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                                break;
                            }
                        case Type dateType when dateType == typeof(DateTime) || dateType == typeof(DateTime?):
                            {
                                helper = helper.MapTimeStamp("\"" + prop.Name + "\"", x => (DateTime?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                                break;
                            }
                        case Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?):
                            {
                                helper = helper.MapMoney("\"" + prop.Name + "\"", x => (decimal?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                                break;
                            }
                        case Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?):
                            {
                                helper = helper.MapDouble("\"" + prop.Name + "\"", x => (double?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                                break;
                            }
                        case Type floatType when floatType == typeof(float) || floatType == typeof(float?):
                            {
                                helper = helper.MapReal("\"" + prop.Name + "\"", x => (float?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                                break;
                            }
                        case Type guidType when guidType == typeof(Guid):
                            {
                                helper = helper.MapUUID("\"" + prop.Name + "\"", x => (Guid)typeof(T).GetProperty(prop.Name).GetValue(x, null));
                                break;
                            }
                    }
                }
                return helper;
            }
    

    나는 (I 엔티티 Undertaking에 지명했다) 그에게 다음과 같은 방법을 사용합니다 :

    var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
    undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
    

    나는 거래와 예를 보여 주었다, 그러나 또한 컨텍스트에서 검색 정상적인 연결을 수행 할 수 있습니다. undertakingsToAdd 내가 DB에 bulkInsert 원하는 일반 엔티티 기록의 열거입니다.

    당신이 사용하고 무료로 마지막으로 쉽게 훨씬 더 빨리 기대 수 있기 때문에 나는 연구와 노력의 몇 시간 후 가지고되는이 솔루션은,입니다! 난 정말 당신뿐만 아니라 위에서 언급 한 이유뿐만 아니라, 그것은 내가 PostgreSQL을 자체에 문제가 없었다있는 유일한 사람이기 때문에,이 솔루션을 사용하는 조언을, 다른 많은 솔루션은 SQLSERVER와 예를 들어 완벽하게 작동합니다.

  25. ==============================

    25.[2019 업데이트] EF 코어 3.1

    [2019 업데이트] EF 코어 3.1

    왔다 무슨 일이 EF 코어에 AutoDetectChangesEnabled을 사용하지 않도록 설정, 위 말했다 다음은 완벽하게 작동 : 삽입 시간 (100)에 의해 분할되었다 (많은 분에서에 몇 초, 크로스 테이블 관계 10K 기록)

    업데이트 된 코드는 다음과 같습니다

      context.ChangeTracker.AutoDetectChangesEnabled = false;
                foreach (IRecord record in records) {
                   //Add records to your database        
                }
                context.ChangeTracker.DetectChanges();
                context.SaveChanges();
                context.ChangeTracker.AutoDetectChangesEnabled = true; //do not forget to re-enable
    
  26. ==============================

    26.비밀은 동일한 빈 스테이징 테이블에 삽입하는 것입니다. 삽입 빠른 번개된다. 그런 다음 주 큰 테이블에 그에서 하나의 삽입을 실행합니다. 그런 다음 배치를위한 준비 테이블이 준비 잘라.

    비밀은 동일한 빈 스테이징 테이블에 삽입하는 것입니다. 삽입 빠른 번개된다. 그런 다음 주 큰 테이블에 그에서 하나의 삽입을 실행합니다. 그런 다음 배치를위한 준비 테이블이 준비 잘라.

    즉.

    insert into some_staging_table using Entity Framework.
    
    -- Single insert into main table (this could be a tiny stored proc call)
    insert into some_main_already_large_table (columns...)
       select (columns...) from some_staging_table
    truncate table some_staging_table
    
  27. ==============================

    27.그러나, 이상 (4000) 인서트는 내가 저장 프로 시저를 사용하는 것이 좋습니다. 경과 시간을 첨부. 나는 "20 그것을 11.788 행을 삽입 않았다

    그러나, 이상 (4000) 인서트는 내가 저장 프로 시저를 사용하는 것이 좋습니다. 경과 시간을 첨부. 나는 "20 그것을 11.788 행을 삽입 않았다

    그것은 코드 이잖아

     public void InsertDataBase(MyEntity entity)
        {
            repository.Database.ExecuteSqlCommand("sp_mystored " +
                    "@param1, @param2"
                     new SqlParameter("@param1", entity.property1),
                     new SqlParameter("@param2", entity.property2));
        }
    
  28. ==============================

    28.데이터를 삽입하기 위해 XML의 형태로 입력 데이터를 취 저장 프로 시저를 사용합니다.

    데이터를 삽입하기 위해 XML의 형태로 입력 데이터를 취 저장 프로 시저를 사용합니다.

    XML로 데이터를 삽입하여 C # 코드 패스에서.

    예컨대에서 C #은, 구문은 다음과 같다 :

    object id_application = db.ExecuteScalar("procSaveApplication", xml)
    
  29. ==============================

    29.엔티티 프레임 워크에서 레코드를 삽입하는 속도를 높이기 위해이 기술을 사용합니다. 여기에서 나는 레코드를 삽입하는 간단한 저장 프로 시저를 사용합니다. 그리고 원시 SQL을 실행 내가 .FromSql를 (사용이 저장 프로 시저) 엔티티 프레임 워크의 방법을 실행합니다.

    엔티티 프레임 워크에서 레코드를 삽입하는 속도를 높이기 위해이 기술을 사용합니다. 여기에서 나는 레코드를 삽입하는 간단한 저장 프로 시저를 사용합니다. 그리고 원시 SQL을 실행 내가 .FromSql를 (사용이 저장 프로 시저) 엔티티 프레임 워크의 방법을 실행합니다.

    CREATE PROCEDURE TestProc
    @FirstParam VARCHAR(50),
    @SecondParam VARCHAR(50)
    
    AS
      Insert into SomeTable(Name, Address) values(@FirstParam, @SecondParam) 
    GO
    

    다음으로, 모든 4000 개 기록을 반복하고 저장된 실행하는 엔티티 프레임 워크 코드를 추가

    절차는 매 100 번째 루프를 onces.

    이를 위해 나는이 프로 시저를 실행 할 문자열 쿼리를 생성, 그 레코드의 모든 세트를 추가 계속.

    그 후 루프 (100)의 배수로 실행을 확인하고 그 경우 .FromSql을 사용하여 실행 ().

    string execQuery = "";
    var context = new MyContext();
    for (int i = 0; i < 4000; i++)
    {
        execQuery += "EXEC TestProc @FirstParam = 'First'" + i + "'', @SecondParam = 'Second'" + i + "''";
    
        if (i % 100 == 0)
        {
            context.Student.FromSql(execQuery);
            execQuery = "";
        }
    }
    
  30. from https://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework by cc-by-sa and MIT license