Tôi có đoạn code sau đây, mà đang bị lỗi:Làm thế nào để sửa chữa siêu chậm truy vấn EF/LINQ thực hiện nhiều câu lệnh SQL
TPM_USER user = UserManager.GetUser(context, UserId);
var tasks = (from t in user.TPM_TASK
where t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
orderby t.DUEDATE, t.PROJECTID
select t);
Dòng đầu tiên, UserManager.GetUser
chỉ cần một tra cứu đơn giản trong cơ sở dữ liệu để có được đúng TPM_USER
bản ghi. Tuy nhiên, dòng thứ hai gây ra tất cả các loại hỗn loạn SQL.
Trước hết, nó thực hiện hai câu lệnh SQL tại đây. Người đầu tiên lấy mỗi hàng đơn trong TPM_TASK
được liên kết với người dùng, đó là đôi khi hàng chục ngàn hàng:
SELECT
-- Columns
FROM TPMDBO.TPM_USERTASKS "Extent1"
INNER JOIN TPMDBO.TPM_TASK "Extent2" ON "Extent1".TASKID = "Extent2".TASKID
WHERE "Extent1".USERID = :EntityKeyValue1
Truy vấn này mất khoảng 18 giây trên người sử dụng với rất nhiều công việc. Tôi mong đợi mệnh đề WHERE cũng chứa các bộ lọc STAGEID, điều này sẽ loại bỏ phần lớn các hàng.
Tiếp theo, có vẻ như để thực hiện một truy vấn mới cho mỗi TPM_PROJECTVERSION
cặp trong danh sách trên:
SELECT
-- Columns
FROM TPMDBO.TPM_PROJECTVERSION "Extent1"
WHERE ("Extent1".PROJECTID = :EntityKeyValue1) AND ("Extent1".VERSIONID = :EntityKeyValue2)
Mặc dù truy vấn này là nhanh chóng, nó thực hiện hàng trăm lần nếu người dùng có nhiệm vụ trong toàn bộ một bó các dự án.
Truy vấn Tôi muốn tạo ra sẽ giống như thế:
SELECT
-- Columns
FROM TPMDBO.TPM_USERTASKS "Extent1"
INNER JOIN TPMDBO.TPM_TASK "Extent2" ON "Extent1".TASKID = "Extent2".TASKID
INNER JOIN TPMDBO.TPM_PROJECTVERSION "Extent3" ON "Extent2".PROJECTID = "Extent3".PROJECTID AND "Extent2".VERSIONID = "Extent3".VERSIONID
WHERE "Extent1".USERID = 5 and "Extent2".STAGEID > 0 and "Extent2".STAGEID <> 3 and "Extent3".STAGEID <= 10
Các truy vấn trên sẽ chạy trong khoảng 1 giây. Thông thường, tôi có thể chỉ định rằng JOIN
bằng cách sử dụng phương thức Include
. Tuy nhiên, điều này dường như không hoạt động trên các thuộc tính. Nói cách khác, tôi không thể làm:
from t in user.TPM_TASK.Include("TPM_PROJECTVERSION")
Có cách nào để tối ưu hóa tuyên bố LINQ này không? Tôi đang sử dụng .NET4 và Oracle là DB phụ trợ.
Giải pháp:
giải pháp này được dựa trên gợi ý Kirk dưới đây, và làm việc kể từ context.TPM_USERTASK
không thể được truy vấn trực tiếp:
var tasks = (from t in context.TPM_TASK.Include("TPM_PROJECTVERSION")
where t.TPM_USER.Any(y => y.USERID == UserId) &&
t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
orderby t.DUEDATE, t.PROJECTID
select t);
Nó không kết quả trong một lồng nhau SELECT
chứ không phải là truy vấn TPM_USERTASK
trực tiếp, nhưng nó có vẻ khá hiệu quả không-ít hơn.
Thật không may, ý tưởng này sẽ không hoạt động. 'TPM_TASK' không có thuộc tính' USERID'. Người dùng liên quan đến các tác vụ thông qua bảng 'TPM_USERTASK', mà bạn không thể truy vấn trực tiếp vì nó được sử dụng trong mối quan hệ nhiều-nhiều. Có lẽ tôi muốn được tốt hơn ra tạo ra một cái nhìn trong cơ sở dữ liệu hoặc một cái gì đó? –
Bạn chắc chắn có thể viết truy vấn để đi ngược lại 'TPM_USERTASK'. Tôi không chắc chắn chính xác lược đồ của bạn được thiết lập như thế nào, nhưng một cái gì đó dọc theo dòng của 'where t.TPM_TASK.Any (y => y.USERID == t.USER)' hoặc chỉ sử dụng 'join' để đưa vào nhiều nhiều. Bạn chắc chắn không được rối tung với quan điểm để đạt được điều này. –
Được rồi, đang rối tung với ý tưởng đó .. Tôi sẽ cho bạn biết sau vài phút .. –