我有下面的代碼,這是行爲不端:如何解決超慢EF/LINQ查詢執行多個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);
第一行,UserManager.GetUser
只是沒有在數據庫中的一個簡單的查詢,以獲得正確的TPM_USER
記錄。但是,第二行會導致各種SQL混亂。
首先,它在這裏執行兩條SQL語句。第一個抓住在TPM_TASK
每一行鏈接到該用戶,有時行數以萬計:
SELECT
-- Columns
FROM TPMDBO.TPM_USERTASKS "Extent1"
INNER JOIN TPMDBO.TPM_TASK "Extent2" ON "Extent1".TASKID = "Extent2".TASKID
WHERE "Extent1".USERID = :EntityKeyValue1
此查詢需要約18秒,有很多任務的用戶。我希望WHERE子句也包含STAGEID篩選器,這將刪除大部分行。
接下來,它似乎執行一個新的查詢每個TPM_PROJECTVERSION
對上面列表中:
SELECT
-- Columns
FROM TPMDBO.TPM_PROJECTVERSION "Extent1"
WHERE ("Extent1".PROJECTID = :EntityKeyValue1) AND ("Extent1".VERSIONID = :EntityKeyValue2)
即使此查詢速度快,它如果用戶在一大堆有任務執行數百倍的項目。
我想生成的查詢看起來是這樣的:
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
上面的查詢會在1秒左右運行。通常,我可以使用Include
方法指定JOIN
。但是,這似乎不適用於屬性。換句話說,我不能這樣做:
from t in user.TPM_TASK.Include("TPM_PROJECTVERSION")
有什麼辦法來優化這個LINQ語句嗎?我使用.NET4和Oracle作爲後端數據庫。
解決方案:
該解決方案是基於以下柯克的建議,並努力因爲context.TPM_USERTASK
不能直接查詢:
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);
它確實結果嵌套SELECT
而不是查詢TPM_USERTASK
直接,但它似乎相當有效的無所謂。
不幸的是,這個想法是行不通的。 'TPM_TASK'沒有'USERID'屬性。用戶通過'TPM_USERTASK'表與任務相關,因爲它用於多對多關係,所以無法直接查詢。也許我最好在數據庫中創建一個視圖或什麼? –
您當然也可以編寫查詢來針對'TPM_USERTASK'。我不確定你的模式是如何設置的,但是沿着'where t.TPM_TASK.Any(y => y.USERID == t.USER)'的行或者只是使用'join'來引入很多很多。你絕對不要爲了達到這個目的而搞亂觀點。 –
好吧,搞砸了那個想法..我會在幾分鐘之內讓你知道.. –