2013-06-12 35 views
9

Khi tôi sử dụng đối tượng xxxContext của mình và phát hành một số Thêm vào bảng, sau đó SaveChanges() cách khung thực thể giải quyết vấn đề này với SQL như thế nào? Nó sẽ chỉ lặp làm chèn vào xxx hoặc nếu có hàng trăm hàng, nó đủ thông minh để đưa ra lệnh Chèn số lượng lớn không?Khuôn khổ thực thể .NET Chèn và chèn số lượng lớn

Câu hỏi thưởng: Nếu nó không phát hành Chèn hàng loạt có cách nào để ép nó để hiệu suất DB của tôi không bị giết bởi chèn riêng biệt? Hoặc để số lượng lớn đến một bảng tạm thời sau đó hợp nhất với bảng ban đầu như một Upsert?

+1

Sử dụng SqlBulkCopy API – ErikEJ

+0

thể trùng lặp của [Way nhanh nhất của Chèn trong Entity Framework] (http://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework) –

+0

Khuôn khổ thực thể rất chậm cho việc này. Tìm thấy một cách để làm điều đó nhanh hơn nhiều. Về cơ bản bạn chèn hàng loạt vào một bảng tạm thời sau đó đưa ra một hợp nhất từ ​​đó vào bảng chính. Tôi đã giải thích kỹ thuật này trên blog của tôi tại đây: http://www.jarloo.com/c-bulk-upsert-to-sql-server-tutorial/ Mô tả kỹ thuật và hiển thị mã cách thực hiện. – Kelly

Trả lời

6

Sự sụp đổ của bất kỳ công cụ ORM nào là nó "trò chuyện". Hầu hết thời gian này là đủ tốt. Đôi khi nó không phải là.

Câu trả lời ngắn gọn là "không".

Đó là lý do tại sao đôi khi tôi chọn IDataReader qua EF hoặc NHibernate, v.v. Và đối với thao tác chèn hàng loạt, tôi gửi xml đến quy trình được lưu trữ và tôi băm nhỏ và chèn/cập nhật hàng loạt hoặc hợp nhất từ ​​đó. Vì vậy, ngay cả khi tôi sử dụng ORM, tôi tạo ra một thư viện miền không phải là EF (hoặc NHibernate) phụ thuộc ...... vì vậy tôi có một "van an toàn" để vượt qua ORM trong các tình huống nhất định.

+0

Cảm ơn, những gì tôi nghĩ. Ngạc nhiên là không có bất kỳ giải pháp OpenSource nào có thỏa thuận với điều này. Dự án của tôi viết hàng ngàn bản ghi cùng một lúc với db và điều này xảy ra sau mỗi 15 giây vì vậy tôi đoán tôi sẽ dính vào sql đơn giản, nơi tôi có thể kiểm soát nó tốt hơn. – Kelly

+0

Đây là điều quan trọng. Việc tái tạo chỉ mục là chậm lại. Khi bạn chèn RBAR (hàng bằng hàng agonizing), bạn phải tạo lại chỉ mục sau mỗi lần chèn. Vì vậy, bạn làm một cái gì đó "thiết lập dựa", giống như đi qua xml, băm nhỏ nó, sau đó làm một chèn vào dbo.MyTable chọn (bó hàng) từ một cái gì đó. Bây giờ, bạn có thể làm một số voodoo, nơi bạn chèn vào một bảng dàn dựng, và sau đó phát hành một "di chuyển từ dàn đến thực" (một cách số lượng lớn), nhưng nó không phải rất EF'ish. Nhưng một lần nữa, quy tắc của ngón tay cái (hoặc một trong những cái chính) là "làm thế nào là các chỉ mục của tôi được xây dựng lại khi tôi làm theo cách này". Aka, vật bị lãng quên – granadaCoder

+0

Phần lớn những gì tôi làm về cơ bản là một sự hận thù. (cập nhật hoặc chèn) Tôi cần chúng để được nhanh chóng và các bảng tôi upsert để có hàng tỷ (gần nghìn tỷ) của hàng. Cách tiếp cận nhanh nhất mà tôi đã tìm thấy là chèn vào một bảng tạm thời sau đó thực hiện hợp nhất. Tôi đã ghi lại nó ở đây: http://www.jarloo.com/c-bulk-upsert-to-sql-server-tutorial/ – Kelly

0

Tôi e rằng EF không hỗ trợ chèn hoặc cập nhật hàng loạt. Như bạn đã nói, EF sẽ tạo ra các lệnh Chèn và thực hiện chúng một cách riêng biệt (nhưng tất cả được bao bọc trong một giao dịch đơn lẻ). Có một số kế hoạch để thực hiện đợt, không chắc chắn nếu có một số tiến bộ gần đây. Hy vọng rằng trong EF6 nhưng tôi bằng cách nào đó nghi ngờ.

Bạn có thể đọc thêm trong số này discussion.

3

Nếu truy vấn chèn của bạn là ANSI SQL hoặc bạn không quan tâm đến việc hỗ trợ cơ sở dữ liệu multipe với codebase của bạn, bạn vẫn có backdoor để tạo ra một nhà cung cấp ADO.NET từ EF và thực hiện một số SQL liệu cuộc gọi

https://stackoverflow.com/a/1579220/98491

tôi sẽ làm một cái gì đó như thế này

private void BulkInsert(IEnumerable<Person> Persons) 
{ 

    // use the information in the link to get your connection 
    DbConnection conn = ... 
    using (DbCommand cmd = conn.CreateCommand()) 
    { 

     var sb = new StringBuilder(); 
     sb.Append("INSERT INTO person (firstname, lastname) VALUES "); 
     var count = 0; 
     foreach(var person in persons) 
     { 
      if (count !=0) sb.Append(","); 
      sb.Append(GetInsertCommand(person, count++, cmd)); 
     } 

     if (count > 0) 
     { 
      cmd.CommandText = sb.ToString(); 
      cmd.ExecuteNonQuery(); 
     } 
    } 



    if (sb.Length > 0) 
     ExecuteNonQuery(sb.ToString()); 
} 

private string GetInsertCommand(Person person, int count, DbCommand cmd) 
{ 
    var firstname = "@firstname" + count.ToString(); 
    var lastname = "@lastname" + count.ToString(); 
    cmd.Parameters.Add(firstname, person.Firstname); 
    cmd.Parameters.Add(lastname, person.Firstname); 
    return String.Format("({0},{1})", firstname, lastname); 
} 

tôi phải thừa nhận tôi đã không kiểm tra nó nhưng điều này phải là một phương pháp nhanh chóng và dơ bẩn để bỏ qua EF đối với một số chèn số lượng lớn cho đến khi chèn hàng loạt là một phần của lõi .

Cập nhật

Chỉ cần một ý tưởng nhanh chóng. Bạn đã thử phương thức ... từ không gian tên Migrations chưa? Có lẽ cái này không chèn số lượng lớn, đã không nhìn vào nó nhưng nó rất đáng để thử:

private void BatchInsert(IEnumerable<Person> persons) 
{ 
    context.Persons.AddOrUpdate(persons); 
} 

Tôi biết phương pháp này có thể được làm chậm nếu bạn xác định một cột chính như AddOrUpdate(p => p.Firstname, persons) nhưng tôi sẽ đoán mà không xac định nó , mà phải được tất cả chèn (không được bảo đảm)

+0

'AddOrUpdate' mà không có thông số lambda sử dụng thuộc tính khóa để truy vấn, vì vậy về cơ bản nó giống hệt với 'AddOrUpdate (p => p.Id, người)'. Nó vẫn sẽ là một truy vấn ('SingleOrDefault' bởi khóa) cho mỗi người trong bộ sưu tập trước khi nó chèn. – Slauma

+0

Cảm ơn bạn đã cập nhật, điều cần biết. –

3

có oportunity cho một số cải tiến trong Entity Framework:

Set:

yourContext.Configuration.AutoDetectChangesEnabled = false; 
yourContext.Configuration.ValidateOnSaveEnabled = false; 

Làm SaveChanges() trong các gói 100 lần chèn ... thử với 1000 và xem các thay đổi.

Vì trong suốt quá trình chèn này, ngữ cảnh giống nhau, bạn có thể xây dựng lại đối tượng ngữ cảnh của mình mỗi 1000 lần chèn. var yourContext = new YourContext();

Thực hiện những cải thiện này trong quá trình nhập dữ liệu của tôi, mất từ ​​7 phút đến 6 giây.

Số thực tế ... không thể là 100's o 1000 trong trường hợp của bạn ... hãy thử nó và tweek nó.

+0

Tôi có một di chuyển khá phức tạp, nơi tôi cũng đang sử dụng lớp UoW/Repo và điều này đã tiết kiệm được một lượng đáng kể thời gian di chuyển cho tôi. Không chắc chắn tôi có thể sử dụng EntityFramework.BulkInsert cho dòng chảy của việc thu thập và lưu dữ liệu trong ứng dụng giao diện điều khiển của tôi. – wintercyborg

2

bạn có thể sử dụng bulk insert extension

sử dụng:

using EntityFramework.BulkInsert.Extensions; 

context.BulkInsert(myEntities); 

với DbContext:

using (var ctx = GetContext()) 
{ 
    using (var transactionScope = new TransactionScope()) 
    { 
     // some stuff in dbcontext  
     ctx.BulkInsert(entities);  
     ctx.SaveChanges(); 
     transactionScope.Complete(); 
    } 
} 
0

ASP NET Lõi phiên bản phương pháp nhanh chóng chèn từ Repository.

public virtual void AddRangeFastAndCommit(IEnumerable<T> entities) 
{ 
    MyDbContext localContext = new MyDbContext(_context.Options); 
    localContext.ChangeTracker.AutoDetectChangesEnabled = false; 

    foreach (var entity in entities) 
    { 
     localContext.Add(entity); 
    } 

    localContext.SaveChanges(); 
    localContext.Dispose(); 
} 
Các vấn đề liên quan