Khuôn khổ thực thể luôn sử dụng các hằng số trong SQL được tạo cho các giá trị được cung cấp cho Skip()
và Take()
.Khung thực thể Force để sử dụng tham số SQL để sử dụng lại bộ đệm SQL proc tốt hơn
Trong ví dụ cực kỳ đơn giản dưới đây:
int x = 10;
int y = 10;
var stuff = context.Users
.OrderBy(u => u.Id)
.Skip(x)
.Take(y)
.Select(u => u.Id)
.ToList();
x = 20;
var stuff2 = context.Users
.OrderBy(u => u.Id)
.Skip(x)
.Take(y)
.Select(u => u.Id)
.ToList();
mã trên tạo ra các truy vấn SQL sau:
SELECT TOP (10)
[Extent1].[Id] AS [Id]
FROM (SELECT [Extent1].[Id] AS [Id], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[User] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > 10
ORDER BY [Extent1].[Id] ASC
SELECT TOP (10)
[Extent1].[Id] AS [Id]
FROM (SELECT [Extent1].[Id] AS [Id], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[User] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > 20
ORDER BY [Extent1].[Id] ASC
Kết quả trong 2 kế hoạch Adhoc thêm vào bộ nhớ cache SQL proc với 1 sử dụng mỗi .
Những gì tôi muốn thực hiện là để parameterize logic Skip()
và Take()
nên các truy vấn SQL sau đây được tạo ra:
EXEC sp_executesql N'SELECT TOP (@p__linq__0)
[Extent1].[Id] AS [Id]
FROM (SELECT [Extent1].[Id] AS [Id], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[User] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > @p__linq__1
ORDER BY [Extent1].[Id] ASC',N'@p__linq__0 int,@p__linq__1 int',@p__linq__0=10,@p__linq__1=10
EXEC sp_executesql N'SELECT TOP (@p__linq__0)
[Extent1].[Id] AS [Id]
FROM (SELECT [Extent1].[Id] AS [Id], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[User] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > @p__linq__1
ORDER BY [Extent1].[Id] ASC',N'@p__linq__0 int,@p__linq__1 int',@p__linq__0=10,@p__linq__1=20
Điều này dẫn đến 1 kế hoạch chuẩn bị bổ sung vào bộ nhớ cache SQL proc với 2 mục đích sử dụng.
Tôi có một số truy vấn khá phức tạp và đang gặp phải chi phí đáng kể (ở phía máy chủ SQL) trong lần chạy đầu tiên và thực thi nhanh hơn trên các lần chạy tiếp theo (vì nó có thể sử dụng bộ đệm kế hoạch). Lưu ý rằng các truy vấn nâng cao hơn này đã sử dụng sp_executesql vì các giá trị khác được tham số hóa nên tôi không quan tâm đến khía cạnh đó.
Bộ truy vấn đầu tiên được tạo ở trên về cơ bản có nghĩa là bất kỳ logic phân trang nào sẽ tạo mục nhập mới trong bộ đệm kế hoạch cho từng trang, làm đầy bộ nhớ cache và yêu cầu phát sinh chi phí phát sinh cho từng trang.
Tôi có thể buộc Khung thực thể tham số hóa các giá trị không? Tôi đã nhận thấy các giá trị khác, ví dụ: trong mệnh đề Where
, đôi khi nó tham số hóa giá trị và đôi khi nó sử dụng hằng số.
Tôi có hoàn toàn không dùng bữa trưa không? Có lý do nào khiến hành vi hiện tại của Entity Framework tốt hơn hành vi mà tôi mong muốn không?
Chỉnh sửa: Trong trường hợp có liên quan, tôi nên đề cập rằng tôi đang sử dụng Khuôn khổ thực thể 4.2.
Chỉnh sửa 2: Câu hỏi này không phải là một bản sao của Entity Framework/Linq to SQL: Skip & Take, mà chỉ đơn thuần là hỏi làm thế nào để đảm bảo rằng Skip
và Take
thực hiện trong SQL thay vì trên máy khách. Câu hỏi này liên quan đến việc tham số hóa các giá trị này.
Liên kết này giải thích cách bạn có thể sử dụng LINQ với SQL Params bạn sẽ phải cuộn xuống cuối liên kết để xem giải thích và ví dụ trang LinqPad - http://www.linqpad.net/WhyLINQBeatsSQL.aspx – MethodMan
Tuyệt vời quan sát. Tôi thường không sử dụng EF cho các dự án "thực", chỉ chơi đùa với những thứ nhỏ nhặt, và không bao giờ nhận thấy hành vi này trước đây. Nếu EF không tham số hóa mọi thứ có thể, thì tôi cho rằng một lỗ hổng lớn. – CodingWithSpike
câu hỏi hay - bạn nghĩ rằng họ đã tối ưu hóa cho việc tái sử dụng kế hoạch có thể là – BrokenGlass