CẬP NHẬT 3: Theo thông báo này , điều này đã được nhóm EF giải quyết trong EF6 alpha 2.
CẬP NHẬT 2: Tôi đã tạo một đề xuất để khắc phục sự cố này. Để bỏ phiếu cho nó, hãy vào đây .
Hãy xem xét một cơ sở dữ liệu SQL với một bảng rất đơn giản.
CREATE TABLE Main (Id INT PRIMARY KEY)
Tôi điền vào bảng với 10.000 bản ghi.
WITH Numbers AS
(
SELECT 1 AS Id
UNION ALL
SELECT Id + 1 AS Id FROM Numbers WHERE Id <= 10000
)
INSERT Main (Id)
SELECT Id FROM Numbers
OPTION (MAXRECURSION 0)
Tôi tạo một mô hình EF cho bảng và chạy truy vấn sau trong LINQPad (Tôi đang sử dụng chế độ "Câu lệnh C #" nên LINQPad không tự động tạo kết xuất).
var rows =
Main
.ToArray();
Thời gian thực hiện ~ 0,07 giây. Bây giờ tôi thêm toán tử Chứa và chạy lại truy vấn.
var ids = Main.Select(a => a.Id).ToArray();
var rows =
Main
.Where (a => ids.Contains(a.Id))
.ToArray();
Thời gian thực hiện cho trường hợp này là 20,14 giây (chậm hơn 288 lần)!
Lúc đầu, tôi nghi ngờ rằng T-SQL được phát ra cho truy vấn mất nhiều thời gian hơn để thực thi, vì vậy tôi đã thử cắt và dán nó từ ngăn SQL của LINQPad vào SQL Server Management Studio.
SET NOCOUNT ON
SET STATISTICS TIME ON
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Primary] AS [Extent1]
WHERE [Extent1].[Id] IN (1,2,3,4,5,6,7,8,...
Và kết quả là
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 88 ms.
Tiếp theo, tôi nghi ngờ LINQPad gây ra sự cố, nhưng hiệu suất vẫn như nhau cho dù tôi chạy nó trong LINQPad hay trong một ứng dụng bảng điều khiển.
Vì vậy, có vẻ như vấn đề nằm ở đâu đó trong Entity Framework.
Tôi đang làm gì đó sai ở đây? Đây là phần quan trọng về thời gian trong mã của tôi, vậy tôi có thể làm gì để tăng tốc hiệu suất không?
Tôi đang sử dụng Entity Framework 4.1 và Sql Server 2008 R2.
CẬP NHẬT 1:
Trong cuộc thảo luận bên dưới, có một số câu hỏi về việc liệu sự chậm trễ xảy ra trong khi EF đang tạo truy vấn ban đầu hay trong khi phân tích dữ liệu mà nó nhận được trở lại. Để kiểm tra điều này, tôi đã chạy đoạn mã sau,
var ids = Main.Select(a => a.Id).ToArray();
var rows =
(ObjectQuery<MainRow>)
Main
.Where (a => ids.Contains(a.Id));
var sql = rows.ToTraceString();
buộc EF phải tạo truy vấn mà không cần thực thi nó đối với cơ sở dữ liệu. Kết quả là mã này yêu cầu ~ 20 giây để chạy, vì vậy có vẻ như gần như toàn bộ thời gian được dành cho việc xây dựng truy vấn ban đầu.
Sau đó, CompiledQuery để giải cứu? Không quá nhanh ... CompiledQuery yêu cầu các tham số được truyền vào truy vấn phải là các kiểu cơ bản (int, string, float, v.v.). Nó sẽ không chấp nhận mảng hoặc IEnumerable, vì vậy tôi không thể sử dụng nó cho danh sách Id.
var qry = Main.Where (a => ids.Contains(a.Id)); var rows = qry.ToArray();
xem phần nào của truy vấn đang chiếm thời gian chưa?