Tại sao việc chèn các thực thể trong EF 4.1 quá chậm so với ObjectContext?


81

Về cơ bản, tôi chèn 35000 đối tượng trong một giao dịch:

using(var uow = new MyContext()){
  for(int i = 1; i < 35000; i++) {
     var o = new MyObject()...;
     uow.MySet.Add(o);
  }
  uow.SaveChanges();
}

Điều này mất mãi mãi! Nếu tôi sử dụng ObjectContext bên dưới (bằng cách sử dụng IObjectAdapter), nó vẫn chậm nhưng mất khoảng 20 giây. Có vẻ như DbSet<>đang thực hiện một số tìm kiếm tuyến tính, mất một lượng thời gian bình phương ...

Có ai khác gặp vấn đề này không?


3
Tôi bằng cách nào đó tin rằng câu trả lời sẽ tương tự như thế này: stackoverflow.com/questions/5917478/…
Ladislav Mrnka

Câu trả lời:


128

Như đã được Ladislav chỉ ra trong nhận xét, bạn cần tắt tính năng phát hiện thay đổi tự động để cải thiện hiệu suất:

context.Configuration.AutoDetectChangesEnabled = false;

Tính năng phát hiện thay đổi này được bật theo mặc định trong DbContextAPI.

Lý do tại sao DbContexthoạt động rất khác với ObjectContextAPI là nhiều chức năng của DbContextAPI sẽ gọi DetectChangesnội bộ hơn các chức năng của ObjectContextAPI khi tính năng phát hiện thay đổi tự động được bật.

Tại đây, bạn có thể tìm thấy danh sách các hàm được gọi DetectChangestheo mặc định. Họ đang:

  • Các Add, Attach, Find, Local, hoặc Removecác thành viên trênDbSet
  • Các GetValidationErrors, Entryhoặc SaveChangescác thành viên trênDbContext
  • Các Entriesphương pháp trênDbChangeTracker

Đặc biệt là Addcác cuộc gọi DetectChangeschịu trách nhiệm về hiệu suất kém mà bạn gặp phải.

Tôi trái ngược với điều này, ObjectContextAPI DetectChangeschỉ gọi tự động trong SaveChangeschứ không gọi trong AddObjectvà các phương thức tương ứng khác được đề cập ở trên. Đó là lý do tại sao hiệu suất mặc định của ObjectContextnhanh hơn.

Tại sao họ giới thiệu tính năng phát hiện thay đổi tự động mặc định này DbContexttrong rất nhiều chức năng? Tôi không chắc lắm, nhưng có vẻ như việc vô hiệu hóa nó và gọi DetectChangestheo cách thủ công tại các điểm thích hợp được coi là nâng cao và có thể dễ dàng đưa các lỗi nhỏ vào ứng dụng của bạn, vì vậy hãy sử dụng [nó] một cách cẩn thận .


@Ladislav: Bạn nói đúng, tôi không tìm thấy cái này vì tôi chỉ đang tìm kiếm các vấn đề chèn :-(
Hartmut

Cảm ơn vì lời giải thích. Tôi thực sự đang gọi context.Configuration.AutoDetectChangesEnabled = false nhưng tôi đã thực hiện nó trong quá trình xây dựng cơ sở dữ liệu trong phương thức Seed (). Tôi nghĩ điều này sẽ đặt mặc định. Tôi không biết rằng tôi phải gọi nó cho từng trường hợp. Cảm ơn!
Hartmut

3
@Hartmut: Bạn có thể vô hiệu hóa tính năng phát hiện thay đổi bên trong hàm tạo của DbContext dẫn xuất của bạn, sau đó bạn luôn tắt tính năng này. Nhưng cá nhân bằng cách nào đó nhận xét này về việc "có khả năng đưa ra các lỗi tinh vi" khi nó bị vô hiệu hóa khiến tôi lo lắng. Tôi đã bật tính năng phát hiện thay đổi theo mặc định và chỉ vô hiệu hóa nó trong các khối mã giống như khối mã của bạn, nơi việc tăng hiệu suất là rõ ràng và tôi cảm thấy an toàn rằng nó không gây ra sự cố.
Slauma

Tôi đồng ý, tôi chỉ đang kiểm tra một số phần quan trọng về hiệu suất trong ứng dụng của mình. Trong mã sản xuất, tốt nhất là giới hạn nó trong các trường hợp như chèn số lượng lớn, v.v.
Hartmut

Cảm ơn bạn vì câu trả lời này. Có rất nhiều thông tin, nhưng điều này cắt ngang với cuộc rượt đuổi!
Fred Wilson

12

Thử nghiệm kinh nghiệm nhỏ với EF 4.3 Code Đầu tiên:

Đã xóa 1000 đối tượng với AutoDetectChanges = true: 23 giây

Đã xóa 1000 đối tượng với AutoDetectChanges = false: 11 giây

Đã chèn 1000 đối tượng bằng AutoDetectChanges = true: 21 giây

Đã chèn 1000 đối tượng bằng AutoDetectChanges = false: 13 giây


1
Cảm ơn Zax. Kết quả của bạn là gì với 35.000 cho mỗi câu hỏi? Bạn sẽ thấy rằng trong câu hỏi ban đầu nó tsates rằng hiệu suất giảm bậc hai
Daniel Dyson

9

Trong .netcore 2.0, điều này đã được chuyển đến:

context.ChangeTracker.AutoDetectChangesEnabled = false;


1

Bên cạnh những câu trả lời bạn đã tìm thấy ở đây. Điều quan trọng cần biết là ở cấp độ cơ sở dữ liệu, việc chèn nhiều hơn là thêm. Cơ sở dữ liệu phải mở rộng / cấp phát không gian mới. Sau đó, nó phải cập nhật ít nhất chỉ mục khóa chính. Mặc dù các chỉ mục cũng có thể được cập nhật khi cập nhật, nhưng nó ít phổ biến hơn rất nhiều. Nếu có bất kỳ khóa ngoại nào, nó cũng phải đọc các chỉ mục đó để đảm bảo tính toàn vẹn của tham chiếu được duy trì. Các trình kích hoạt cũng có thể đóng một vai trò nào đó mặc dù chúng có thể ảnh hưởng đến các bản cập nhật theo cùng một cách.

Tất cả những gì cơ sở dữ liệu hoạt động có ý nghĩa trong hoạt động chèn hàng ngày bắt nguồn bởi các mục nhập của người dùng. Nhưng nếu bạn chỉ đang tải lên một cơ sở dữ liệu hiện có hoặc có một quá trình tạo ra rất nhiều phụ trang. Bạn có thể muốn xem xét các cách để tăng tốc độ, bằng cách trì hoãn nó đến cùng. Thông thường, vô hiệu hóa các chỉ mục trong khi chèn là một cách phổ biến. Có những cách tối ưu hóa rất phức tạp có thể được thực hiện tùy thuộc vào từng trường hợp, chúng có thể hơi áp đảo.

Chỉ biết rằng nói chung việc chèn sẽ mất nhiều thời gian hơn so với cập nhật.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.