簡體   English   中英

了解 LINQ 如何編譯為 ADO.NET SQL 語句

[英]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')

以下是我的問題:

  1. 為什么 LINQ 對 14 個簡單選擇進行流派而不是單個選擇與連接和 where?
  2. 我怎樣才能加快我認為是一段簡單代碼的速度?

在方法的第一部分中, 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.

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