Khung thực thể quá chậm. Những lựa chọn của tôi là gì? [đóng cửa]


93

Tôi đã làm theo câu thần chú "Không tối ưu hóa sớm" và mã hóa Dịch vụ WCF của mình bằng Entity Framework.

Tuy nhiên, tôi đã lập hồ sơ hiệu suất và Entity Framework quá chậm. (Ứng dụng của tôi xử lý 2 tin nhắn trong khoảng 1,2 giây, trong đó ứng dụng (kế thừa) mà tôi đang viết lại thực hiện 5-6 tin nhắn cùng một lúc.

Hồ sơ của tôi trỏ đến Khung thực thể chiếm phần lớn thời gian cho mỗi tin nhắn.

Thế ý kiến ​​của tôi là gì?

  • Có ORM tốt hơn ngoài đó không?
    (Một cái gì đó chỉ hỗ trợ đọc và ghi các đối tượng bình thường và chạy nhanh ..)

  • Có cách nào để làm cho Entity Framework nhanh hơn không?
    ( Lưu ý : khi tôi nói nhanh hơn có nghĩa là trong thời gian dài, không phải cuộc gọi đầu tiên. (Cuộc gọi đầu tiên chậm (15 giây cho một tin nhắn), nhưng đó không phải là vấn đề. Tôi chỉ cần nó nhanh cho phần còn lại trong số các tin nhắn.)

  • Tùy chọn thứ 3 bí ẩn nào đó sẽ giúp tôi tăng tốc độ sử dụng dịch vụ của mình.

LƯU Ý: Hầu hết các tương tác DB của tôi là Tạo và Cập nhật. Tôi thực hiện rất ít việc chọn và xóa.


Điều này nghe có vẻ giống như một bản rehash của 'linq là chậm' làm sao bạn biết đó là EF? Bạn đã lập hồ sơ tất cả các thay đổi của mình?
Maess

6
Một số câu trả lời chỉ đến các truy vấn. Theo kinh nghiệm của tôi, sự chậm chạp trong EF ít liên quan đến các truy vấn mà thay vào đó là chi phí thực hiện và những chi phí đó thường gắn với theo dõi thay đổi và điều đó ảnh hưởng như thế nào đến (các) phiên bản được tạo. Thật không may, tôi không có một viên đạn bạc cho bạn vì vậy đây chỉ là một nhận xét, nhưng tôi khuyên bạn nên xem liệu việc lập hồ sơ có tiết lộ chi phí vật chất hóa cao hay không và nếu có, hãy nghiên cứu xem có thể làm gì về chi phí đã nêu.
Anthony Pegram

@Maess - Tôi nghĩ rằng tôi đã chỉ ra rằng tôi đã lập hồ sơ và nhận thấy rằng EF / DB chạy chậm. Dù bằng cách nào, tôi đã làm. Tôi đã lập hồ sơ và tương tác EF / DB là thủ phạm chính.
Vaccano

@Anthony - Không phải việc vật chất hóa trước hết là một việc làm sao? Nếu vậy, bạn đúng rằng nó rất chậm. Lần chạy đầu tiên là siêu chậm. Nhưng như tôi đã chỉ ra, tôi không quá lo lắng về điều đó. Đó là tổng thông lượng là vấn đề. (Nếu đó không phải là những gì thể hóa là sau đó tôi cần phải vì vậy một số nghiên cứu để xem nếu nó là nguyên nhân của vấn đề của tôi)
Vaccano

1
@Vaccano, không, cụ thể hóa là quá trình lấy dữ liệu từ cơ sở dữ liệu và khởi tạo và điền vào biểu đồ của các đối tượng để biểu diễn dữ liệu đó. Tôi không nói về hiệu suất lần chạy đầu tiên vì mã được lắp ghép (hoặc thậm chí khi Máy chủ Sql có thể tạo kế hoạch thực thi truy vấn), nhưng điều gì sẽ xảy ra mỗi khi bạn lấy dữ liệu ở dạng đối tượng.
Anthony Pegram

Câu trả lời:


46

Bạn nên bắt đầu bằng cách cấu hình các lệnh SQL do Entity Framework thực sự phát hành. Tùy thuộc vào cấu hình của bạn (POCO, các thực thể Tự theo dõi) có rất nhiều chỗ để tối ưu hóa. Bạn có thể gỡ lỗi các lệnh SQL (không nên khác nhau giữa chế độ gỡ lỗi và phát hành) bằng ObjectSet<T>.ToTraceString()phương pháp này. Nếu bạn gặp một truy vấn yêu cầu tối ưu hóa hơn nữa, bạn có thể sử dụng một số phép chiếu để cung cấp cho EF thêm thông tin về những gì bạn đang cố gắng hoàn thành.

Thí dụ:

Product product = db.Products.SingleOrDefault(p => p.Id == 10);
// executes SELECT * FROM Products WHERE Id = 10

ProductDto dto = new ProductDto();
foreach (Category category in product.Categories)
// executes SELECT * FROM Categories WHERE ProductId = 10
{
    dto.Categories.Add(new CategoryDto { Name = category.Name });
}

Có thể được thay thế bằng:

var query = from p in db.Products
            where p.Id == 10
            select new
            {
                p.Name,
                Categories = from c in p.Categories select c.Name
            };
ProductDto dto = new ProductDto();
foreach (var categoryName in query.Single().Categories)
// Executes SELECT p.Id, c.Name FROM Products as p, Categories as c WHERE p.Id = 10 AND p.Id = c.ProductId
{
    dto.Categories.Add(new CategoryDto { Name = categoryName });
}

Tôi chỉ gõ nó ra khỏi đầu, vì vậy đây không phải là chính xác cách nó sẽ được thực thi, nhưng EF thực sự thực hiện một số tối ưu hóa tốt nếu bạn cho nó biết mọi thứ bạn biết về truy vấn (trong trường hợp này, chúng tôi sẽ cần danh mục- tên). Nhưng điều này không giống như tải nhanh (db.Products.Include ("Danh mục")) vì các phép chiếu có thể làm giảm thêm lượng dữ liệu cần tải.


40
Câu trả lời này nghe có vẻ hợp lý, cho đến khi bạn nhận ra rằng không thể truy cập các loại ẩn danh bên ngoài phương pháp mà chúng được xác định. Nếu bạn muốn tải lên một đối tượng phức tạp và không viết một megamoth, thì bạn cần phải giải mã hóa các loại ẩn danh mới của mình thành một loại POCO nào đó. Một lần nữa, điều đó nghe có vẻ hợp lý cho đến khi bạn nhận ra rằng khi làm như vậy, về cơ bản bạn đã VIẾT LẠI KHUNG KHUNG QUYỀN CỦA RIÊNG BẠN. Thật là nhảm nhí.
Doug

5
điều này dẫn đến tốc độ tăng 15x-20x đối với tôi.
Dave Cousineau

11
Câu trả lời thú vị và hữu ích, vẫn còn giá trị sau một thời gian. @Doug: Điều này không thực sự nhảm nhí vì bạn chỉ tối ưu hóa (sử dụng các phép chiếu) vài truy vấn mà bạn thực sự cần sẽ sử dụng thêm lợi ích. EF và POCO cung cấp cho bạn mặc định hợp lý, điều này rất tốt!
Victor

2
@Doug Hầu hết các ứng dụng đều có các mô hình xem cho các tình huống chỉ xem, phải không? Cũng có thể thực hiện nhiều thao tác ánh xạ khi bạn lấy dữ liệu ra.
Casey

4
Tôi cảm thấy ORM là tương lai. Chúng chỉ có ý nghĩa, cho đến khi tôi bắt đầu sử dụng chúng. Sau đó, tôi tìm thấy Dapper . Bây giờ, khi nhìn thấy những giải pháp như thế này, tôi quặn lòng vì độ phức tạp tăng lên nhanh chóng. Viết SQL trừu tượng trong C # không phải là cách để tồn tại.
Michael Silver

80

Thực tế của vấn đề là các sản phẩm như Entity Framework LUÔN LUÔN sẽ chậm và kém hiệu quả, bởi vì chúng đang thực thi nhiều mã hơn.

Tôi cũng thấy thật ngớ ngẩn khi mọi người đang gợi ý rằng người ta nên tối ưu hóa các truy vấn LINQ, nhìn vào SQL được tạo, sử dụng trình gỡ lỗi, biên dịch trước, thực hiện nhiều bước bổ sung, v.v. tức là lãng phí rất nhiều thời gian. Không ai nói - Hãy đơn giản hóa! Mọi người đều muốn làm mọi thứ thêm phức tạp bằng cách thực hiện nhiều bước hơn nữa (lãng phí thời gian).

Một cách tiếp cận thông thường là hoàn toàn không sử dụng EF hoặc LINQ. Sử dụng SQL thuần túy. Không có gì là sai với nó. Chỉ bởi vì có tâm lý bầy đàn giữa các lập trình viên và họ cảm thấy thôi thúc sử dụng mọi sản phẩm mới hiện có, không có nghĩa là nó tốt hoặc nó sẽ hoạt động. Hầu hết các lập trình viên nghĩ rằng nếu họ kết hợp mọi đoạn mã mới được phát hành bởi một công ty lớn, điều đó đang khiến họ trở thành một lập trình viên thông minh hơn; không đúng chút nào. Lập trình thông minh chủ yếu là về cách làm được nhiều việc hơn mà ít phải đau đầu, không chắc chắn và tốn ít thời gian nhất. Nhớ thời gian! Đó là yếu tố quan trọng nhất, vì vậy hãy cố gắng tìm cách không lãng phí nó vào việc giải quyết các vấn đề bằng mã xấu / cồng kềnh được viết đơn giản để phù hợp với một số 'mẫu' kỳ lạ được gọi là

Thư giãn, tận hưởng cuộc sống, tạm ngừng viết mã và ngừng sử dụng các tính năng bổ sung, mã, sản phẩm, 'mẫu'. Tuổi thọ ngắn và tuổi thọ của mã của bạn thậm chí còn ngắn hơn, và nó chắc chắn không phải là khoa học tên lửa. Loại bỏ các lớp như LINQ, EF và các lớp khác, và mã của bạn sẽ chạy hiệu quả, sẽ mở rộng quy mô và vâng, nó vẫn sẽ dễ bảo trì. Quá nhiều trừu tượng là một 'khuôn mẫu' xấu.

Và đó là giải pháp cho vấn đề của bạn.


155
Đây là ném em bé ra ngoài với nước tắm. Bạn tối ưu hóa các nút thắt cổ chai, thật ngớ ngẩn khi loại bỏ EF vì nó quá chậm ở một vài nơi, trong khi hầu hết những nơi khác lại rất nhanh. Tại sao không sử dụng cả hai? EF xử lý tốt các thủ tục được lưu trữ và SQL thô. Tôi vừa chuyển đổi một truy vấn LINQ-to-SQL mất hơn 10 giây thành SP mất ~ 1 giây, nhưng tôi sẽ không loại bỏ tất cả LINQ-to-SQL. Nó đã tiết kiệm rất nhiều thời gian trong các trường hợp đơn giản khác, với ít mã hơn và ít chỗ cho lỗi hơn và các truy vấn được trình biên dịch xác minh và khớp với cơ sở dữ liệu. Ít mã hơn thì bảo trì dễ dàng hơn và ít lỗi hơn.
JulianR

11
Nhìn chung, lời khuyên của bạn là tốt, nhưng tôi không nghĩ là đúng khi bỏ EF hoặc các yếu tố trừu tượng khác vì chúng không hoạt động tốt trong 10% thời gian.
JulianR

49
SQL đơn giản = dễ bảo trì? Chỉ không đúng với các ứng dụng rất lớn với nhiều logic nghiệp vụ. Viết SQL phức tạp có thể tái sử dụng không phải là một điều dễ dàng thực hiện. Cá nhân tôi đã gặp một số vấn đề về hiệu suất với EF, nhưng những vấn đề này chỉ đơn giản là không so sánh với lợi ích của ORM thích hợp về mặt RAD và giữ cho mọi thứ KHÔ (nếu có bất kỳ mức độ phức tạp nào liên quan).
MemeDeveloper

13
+ 10 ^ 100 Quá nhiều trừu tượng là một 'mẫu' xấu
Makach

57
-1. "EF LUÔN sẽ chậm và kém hiệu quả." Tôi không hiểu tại sao bạn lại khẳng định điều như thế này là sự thật tuyệt đối. Có nhiều lớp hơn để trải qua sẽ làm cho một cái gì đó chậm hơn, nhưng liệu sự khác biệt đó có LƯU Ý được hay không là hoàn toàn phụ thuộc vào tình huống như số lượng dữ liệu và loại truy vấn được thực thi. Đối với tôi, điều này giống như việc nói 'C # LUÔN LUÔN sẽ chậm và kém hiệu quả' bởi vì nó là một trừu tượng cao hơn C ++. Tuy nhiên, nhiều người chọn sử dụng nó vì năng suất đạt được vượt xa sự suy giảm hiệu suất cân nặng (nếu có). Điều tương tự cũng áp dụng cho EF
Despertar

37

Một gợi ý là chỉ sử dụng LINQ to Entity Framework cho các câu lệnh CRUD một bản ghi.

Đối với các truy vấn, tìm kiếm, báo cáo, v.v. liên quan nhiều hơn, hãy viết một thủ tục được lưu trữ và thêm nó vào mô hình Entity Framework như được mô tả trên MSDN .

Đây là cách tiếp cận mà tôi đã thực hiện với một vài trang web của mình và nó có vẻ là một sự thỏa hiệp tốt giữa năng suất và hiệu suất. Entity Framework sẽ không phải lúc nào cũng tạo ra SQL hiệu quả nhất cho nhiệm vụ hiện có. Và thay vì dành thời gian để tìm hiểu lý do tại sao, viết một thủ tục được lưu trữ cho các truy vấn phức tạp hơn thực sự tiết kiệm thời gian cho tôi. Khi bạn đã quen với quy trình này, không quá phức tạp khi thêm các tài liệu lưu trữ vào mô hình EF của bạn. Và tất nhiên, lợi ích của việc thêm nó vào mô hình của bạn là bạn nhận được tất cả những gì tốt được đánh máy mạnh mẽ đến từ việc sử dụng ORM.


Bạn có ý tưởng về các phương thức được sử dụng trong dàn giáo như db.athlete.find (id), v.v ... Chúng hoạt động như thế nào so với ADO.NET hoặc dapper ??
Đó là một cái bẫy

15

Nếu bạn chỉ đơn thuần là tìm nạp dữ liệu, sẽ giúp ích rất nhiều cho hiệu suất khi bạn yêu cầu EF không theo dõi các thực thể mà nó tìm nạp. Làm điều này bằng cách sử dụng MergeOption.NoTracking. EF sẽ chỉ tạo truy vấn, thực thi nó và giải mã kết quả cho các đối tượng, nhưng sẽ không cố gắng theo dõi các thay đổi của thực thể hoặc bất kỳ thứ gì có tính chất đó. Nếu một truy vấn đơn giản (không mất nhiều thời gian chờ cơ sở dữ liệu trả về), tôi nhận thấy rằng việc đặt nó thành NoTracking có thể tăng gấp đôi hiệu suất truy vấn.

Xem bài viết MSDN này trên enum MergeOption:

Giải pháp nhận dạng, quản lý nhà nước và theo dõi thay đổi

Đây có vẻ là một bài báo hay về hiệu suất EF:

Hiệu suất và Khung thực thể


9
Trước khi bất kỳ ai làm điều này, bạn nên đọc ở đây. stackoverflow.com/questions/9259480/…
leen3o

6

Bạn nói rằng bạn đã lập hồ sơ ứng dụng. Bạn cũng đã lập hồ sơ ORM chưa? Có một hồ sơ EF từ Ayende sẽ nêu bật nơi bạn có thể tối ưu hóa mã EF của mình. Bạn có thể tìm thấy nó ở đây:

http://efprof.com/

Hãy nhớ rằng bạn có thể sử dụng phương pháp SQL truyền thống cùng với ORM nếu bạn cần đạt được hiệu suất.

Nếu có ORM nhanh hơn / tốt hơn? Tùy thuộc vào đối tượng / mô hình dữ liệu của bạn, bạn có thể cân nhắc sử dụng một trong các ORM vi mô, chẳng hạn như Dapper , Massive hoặc PetaPoco .

Trang web Dapper công bố một số điểm chuẩn so sánh sẽ cho bạn biết cách chúng so sánh với các ORM khác. Nhưng điều đáng chú ý là các ORM vi mô không hỗ trợ bộ tính năng phong phú của các ORM đầy đủ như EF và NH.

Bạn có thể muốn xem qua RavenDB . Đây là cơ sở dữ liệu không quan hệ (lại từ Ayende) cho phép bạn lưu trữ POCO trực tiếp mà không cần ánh xạ . RavenDB được tối ưu hóa để đọc và làm cho cuộc sống của các nhà phát triển dễ dàng hơn rất nhiều bằng cách loại bỏ nhu cầu thao tác với lược đồ và ánh xạ các đối tượng của bạn tới lược đồ đó. Tuy nhiên, hãy lưu ý rằng đây là một cách tiếp cận khác đáng kể so với việc sử dụng phương pháp ORM và những điều này được nêu trong trang web của sản phẩm .


3

Tôi đã tìm thấy câu trả lời của @Slauma ở đây rất hữu ích để tăng tốc mọi thứ. Tôi đã sử dụng cùng một loại mẫu cho cả chèn và cập nhật - và hiệu suất tăng vọt.


2

Theo kinh nghiệm của tôi, vấn đề không phải với EF, mà với chính cách tiếp cận ORM.

Nhìn chung, tất cả các ORM đều gặp phải vấn đề N + 1 không phải là các truy vấn được tối ưu hóa và v.v. Tôi đoán tốt nhất là theo dõi các truy vấn gây ra suy giảm hiệu suất và cố gắng tinh chỉnh công cụ ORM hoặc viết lại các phần đó bằng SPROC.


1
Mọi người cứ nói với tôi điều này. Nhưng tôi sẽ thiết lập một câu lệnh lựa chọn đơn giản bằng cách sử dụng ADO cũ và cùng một lựa chọn đơn giản sử dụng ngữ cảnh EF và EF luôn chậm hơn đáng kể. Tôi thực sự muốn thích EF, nhưng nó khiến cuộc sống trở nên khó khăn hơn thay vì dễ dàng hơn.
Sinaesthetic

1
@Sinaesthetic Tất nhiên là chậm hơn. Tương tự, mã được viết bằng Linq to Objects thường chậm hơn mã được viết không có nó. Câu hỏi không thực sự là liệu nó nhanh hơn hay nhanh hơn (làm thế nào nó có thể được, khi ẩn nó vẫn phải đưa ra truy vấn mà bạn đã đưa ra bằng tay?) Nhưng liệu 1) nó vẫn đủ nhanh cho nhu cầu của bạn 2) nó tiết kiệm thời gian bạn viết mã 3) lợi ích bù đắp chi phí. Dựa trên những mục đó, tôi nghĩ EF phù hợp với nhiều dự án.
Casey

@Sinaesthetic Tôi cũng muốn nói thêm rằng nếu bạn không sử dụng ORM, điều xảy ra thường xuyên hơn không phải là mỗi truy vấn SQL được tinh chỉnh và tối ưu hóa mà là ứng dụng kết thúc bằng việc phát triển nội bộ, tự nhiên, kém ORM được hỗ trợ, hoạt động kém hiệu quả, trừ khi nhóm của bạn đặc biệt kỷ luật và rất quan tâm đến hiệu suất.
Casey


1

Tôi cũng gặp phải vấn đề này. Tôi ghét phải đổ vào EF vì nó hoạt động rất tốt, nhưng nó chỉ chậm. Trong hầu hết các trường hợp, tôi chỉ muốn tìm một bản ghi hoặc cập nhật / chèn. Ngay cả những thao tác đơn giản như thế này cũng rất chậm. Tôi đã kéo lại 1100 bản ghi từ một bảng thành một Danh sách và thao tác đó mất 6 giây với EF. Đối với tôi điều này là quá dài, ngay cả việc tiết kiệm cũng mất quá nhiều thời gian.

Tôi đã kết thúc việc tạo ORM của riêng mình. Tôi đã lấy 1100 bản ghi giống nhau từ cơ sở dữ liệu và ORM của tôi mất 2 giây, nhanh hơn nhiều so với EF. Mọi thứ với ORM của tôi gần như ngay lập tức. Hạn chế duy nhất hiện tại là nó chỉ hoạt động với MS SQL Server, nhưng nó có thể được thay đổi để hoạt động với những người khác như Oracle. Tôi sử dụng MS SQL Server cho mọi thứ ngay bây giờ.

Nếu bạn muốn thử ORM của tôi, đây là liên kết và trang web:

https://github.com/jdemeuse1204/OR-M-Data-Entities

Hoặc nếu bạn muốn sử dụng nugget:

PM> Gói cài đặt OR-M_DataEntities

Tài liệu cũng có trên đó


0

Nó chỉ có ý nghĩa khi tối ưu hóa sau khi bạn đã lập hồ sơ. Nếu bạn phát hiện ra rằng truy cập DB chậm, bạn có thể chuyển đổi sang sử dụng các thủ tục được lưu trữ và giữ lại EF. Nếu bạn phát hiện ra rằng chính EF chạy chậm, bạn có thể phải chuyển sang ORM khác hoặc hoàn toàn không sử dụng ORM.


0

Chúng tôi có một ứng dụng tương tự (Wcf -> EF -> cơ sở dữ liệu) thực hiện 120 Yêu cầu mỗi giây một cách dễ dàng, vì vậy tôi chắc chắn rằng EF không phải là vấn đề của bạn ở đây, điều đó đang được nói, tôi đã thấy những cải thiện hiệu suất lớn với các truy vấn đã biên dịch.


98% mã của tôi là Tạo và Cập nhật cuộc gọi. Tôi không biết liệu điều đó có tạo ra sự khác biệt hay không, nhưng nó chậm hơn nhiều so với 120 mỗi giây.
Vaccano

vâng, đó không phải là một ứng dụng điển hình, tôi sẽ đề nghị bạn lập hồ sơ ứng dụng của mình. đối với chúng tôi nó chủ yếu là đọc ...
np-cứng

0

Tôi đã sử dụng EF, LINQ để SQL và dapper. Dapper là nhanh nhất. Ví dụ: Tôi cần 1000 bản ghi chính với 4 bản ghi phụ mỗi bản ghi. Tôi đã sử dụng LINQ để sql, mất khoảng 6 giây. Sau đó, tôi chuyển sang dapper, lấy 2 bộ bản ghi từ thủ tục lưu trữ duy nhất và cho mỗi bản ghi thêm các bản ghi phụ. Tổng thời gian 1 giây.

Ngoài ra thủ tục được lưu trữ sử dụng các hàm giá trị bảng với áp dụng chéo, tôi thấy các hàm giá trị vô hướng rất chậm.

Lời khuyên của tôi là sử dụng EF hoặc LINQ sang SQL và trong một số trường hợp nhất định, hãy chuyển sang dapper.


-1

Khung thực thể không được tự gây ra tắc nghẽn lớn. Rất có thể là có những nguyên nhân khác. Bạn có thể thử chuyển EF sang Linq2SQL, cả hai đều có các tính năng so sánh và mã sẽ dễ chuyển đổi nhưng trong nhiều trường hợp Linq2SQL nhanh hơn EF.

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.