EFCore2.2使用Include進行查詢並排序時性能問題


背景

最近在使用EFCore2.2進行查詢后並排序的過程中發現了一個問題,就是查詢的過程使用了Include后代碼生成的SQL不符合預期,並且性能上面有很大的問題,借此寫一篇文章來進行分析。

1.1 EFCore語句

LinQ語句 _ = _repairContractRepository.GetAll().Include(r => r.RepairContractWorkItems).OrderByDescending(r => r.CreateTime).Take(20).ToList();

  在上面的例子中_repairContractRepository表示的是實體RepairContract的倉儲,在代碼中的定義是:private readonly IRepository<RepairContract, Guid> _repairContractRepository;另外一個RepairContract對應多個RepairContractWorkItem,兩個實體之間是一對多的關系,在EFCore中通過Include方法來一次性查詢出關聯的對象,后面我們將查詢的結果按照主單的CreateTime進行排序並取前20條,我們來看看這條語句生成的SQL是否符合預期。

1.2 生成的SQL語句  

SELECT TOP (20) r.*
FROM [RepairContract] AS [r]
ORDER BY [r].[CreateTime] DESC, [r].[Id]

  明明只是按照CreateTime進行排序,為什么后面會加一個[r].[Id],這個問題該怎么解釋,多了一個按照主單Id升序排列到底有什么影響,我們來看看具體的統計信息。

  圖一 加了導航屬性生成SQL及部分參數統計

   在我們的數據庫中主單RepairContract大概有26萬條數據,我們已經在CreateTime上面創建了索引,按照道理不會這么慢,那我們試着去掉[r].[Id]來看看到底有什么差別。

圖二 未加導航屬性生成SQL及部分參數統計

   結果查詢的時間從5723毫秒一下子降到了3毫秒,性能產生了巨大的提升,為什么會產生這個原因呢?事后發現是因為在查詢的過程中使用了導航屬性Include,去掉這個導航屬性之后就能夠生成符合我們預期的SQL語句了,所以在使用Include查詢並進行排序的過程中一定要注意看最終生成的SQL是否符合預期,至於為什么加了導航屬性后進行排序會多出一部分排序,這個也沒有發現原因。

結論

  其實對於這個問題早在EF框架的時候就有這個問題,你可以看看這篇文章,現階段的解決方式只有在使用導航屬性后盡量不要去Order By操作,如果真要進行排序操作,那么就不要使用Include的導航屬性來直接進行操作,這個在使用EFCore2.2版本的時候需要特別注意。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM