簡體   English   中英

如何修復執行多個SQL語句的超慢EF / LINQ查詢

[英]How to fix super slow EF/LINQ query executing multiple SQL statements

我有以下代碼,這是行為不端:

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作為后端數據庫。

解:

此解決方案基於Kirk的以下建議,並且自context.TPM_USERTASK起作用。無法直接查詢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關系。 它正在拉低附加到該用戶的每個任務,這正是它應該做的事情。 當你這樣做時,沒有ORM SQL翻譯。 您正在獲取用戶,然后將所有任務都放入內存,然后執行一些客戶端過濾。 這都是使用延遲加載完成的,因此SQL會因為無法批量處理而異常低效。

相反,重寫您的查詢以直接針對TPM_TASK並針對用戶進行過濾:

var tasks = (from t in context.TPM_TASK
         where t.USERID == user.UserId && t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
         orderby t.DUEDATE, t.PROJECTID
         select t);

注意我們如何檢查t.USERID == user.UserId 這產生與user.TPM_TASK相同的效果,但現在所有繁重的工作都是由數據庫而不是內存完成的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM