[英]Understanding how LINQ compiles to ADO.NET SQL statements
我有一個看起來非常簡單的 LINQ 語句,但它生成的 SQL 對我來說沒有意義,而且執行時間比我預期的要長得多。 我只是想了解 LINQ 正在做什么,以便我可以弄清楚為什么它運行得如此緩慢。 一個類似的 SQL 語句需要不到一秒鍾,但 LINQ 需要大約 20 秒。
這是代碼:
// This line takes 20 seconds to return.
var alertEvents = GetFilteredAlertEvents(alert.AlertEvents, db).ToList<AlertEvent>();
private static IEnumerable<AlertEvent> GetFilteredAlertEvents(ICollection<AlertEvent> alertEvents, SlalomEREntities db)
{
Guid marketAlertReceiverGroupId = new Guid(ConfigurationManager.AppSettings["MarketAlertReceiverGroupId"]);
var subQuery = from ae in alertEvents
join tr in db.TargetResources on ae.ResourceId equals tr.ResourceID
join atr in db.AlertTargetResources on tr.ResourceID equals atr.TargetResourceID
where atr.AlertTargetID == marketAlertReceiverGroupId
select ae.AlertEventId;
return from alertEvent in alertEvents
where !subQuery.Contains(alertEvent.AlertEventId)
select alertEvent;
}
在 SSMS 中,子選擇返回 3126 行沒有where
,只有 127 行有它。 SSMS 中的主select
返回 365 行而沒有子選擇。 帶有子選擇的完整選擇返回 238 行。 數據不多。
使用 Visual Studio 的診斷工具,我看到 14 個從 LINQ 生成的 SQL 語句。 它們中的每一個都是一個簡單的 SQL 選擇,我沒有看到任何連接,也沒有看到where
比較。 這是我在“診斷工具事件”窗口中看到的示例 SQL 語句:
SELECT
[Extent1].[AlertTargetID] AS [AlertTargetID],
[Extent1].[TargetResourceID] AS [TargetResourceID],
[Extent1].[CreatedAt] AS [CreatedAt],
[Extent1].[CreatedBy] AS [CreatedBy]
FROM [dbo].[AlertTargetResource] AS [Extent1]
還有 13 條類似的 SQL 語句。
這是我試圖復制的 SQL。
select *
from AlertEvent ae1
where ae1.AlertEventId not in
(select ae.AlertEventId
from AlertEvent ae
join TargetResource tr on ae.ResourceId = tr.ResourceID
join AlertTargetResource atr on atr.TargetResourceID = tr.ResourceID
where atr.AlertTargetID = '89bd4ea5-5d56-4b8a-81ba-5a9e5991ba64')
以下是我的問題:
在方法的第一部分中, subQuery
是尚未針對數據庫運行的查詢。 在第二部分(圍繞您的return
語句),您多次調用該查詢。
Entity Framework 如何處理這樣的情況並不總是很明顯,但在這里它似乎為alertEvents
每個項目調用查詢。
您真正想要的是查詢返回的 ID 列表,然后將該列表用於方法的第二部分。 要將查詢轉換為該查詢返回的數據,您可以使用ToList()
。 此擴展方法將執行查詢並返回數據結果。
在下面的代碼中, subQuery
現在是 ID 的集合。
private static IEnumerable<AlertEvent> GetFilteredAlertEvents(ICollection<AlertEvent> alertEvents, SlalomEREntities db)
{
Guid marketAlertReceiverGroupId = new Guid(ConfigurationManager.AppSettings["MarketAlertReceiverGroupId"]);
var subQuery = (from ae in alertEvents
join tr in db.TargetResources on ae.ResourceId equals tr.ResourceID
join atr in db.AlertTargetResources on tr.ResourceID equals atr.TargetResourceID
where atr.AlertTargetID == marketAlertReceiverGroupId
select ae.AlertEventId).ToList();
return from alertEvent in alertEvents
where !subQuery.Contains(alertEvent.AlertEventId)
select alertEvent;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.