簡體   English   中英

了解延遲執行:是否重新執行Linq查詢每次引用其匿名對象集合時?

[英]Understanding Deferred Execution: Is a Linq Query Re-executed Everytime its collection of anonymous objects is referred to?

我目前正在嘗試編寫一些代碼,這些代碼將在兩個單獨的數據庫上運行查詢,並將結果返回給匿名對象。 一旦我有兩個匿名對象集合,我需要對兩個集合進行比較。 比較是我需要檢索webOrders中的所有記錄,但不需要檢索foamOrders中的所有記錄。 目前,我正在使用Linq進行比較。 我的主要問題是兩個原始查詢都返回了大約30,000條記錄,而現在我的代碼需要花費太長時間才能完成。 我是新手使用Linq,所以我試圖理解是否使用Linq比較兩個匿名對象集合實際上會導致數據庫查詢反復運行 - 由於延遲執行。 這可能是一個明顯的答案,但我還沒有非常明確地理解Linq和匿名對象如何使用延遲執行。 我希望有人能夠啟發我。 以下是我的代碼......

private DataTable GetData()
{
    using (var foam = Databases.Foam(false))
    {
        using (MySqlConnection web = new MySqlConnection(Databases.ConnectionStrings.Web(true)
        {
            var foamOrders = foam.DataTableEnumerable(@"
                    SELECT order_id
                    FROM   Orders
                    WHERE  order_id NOT LIKE 'R35%'
                    AND originpartner_code = 'VN000011'
                    AND orderDate > Getdate() - 7 ")
                .Select(o => new
                {
                    order = o[0].ToString().Trim()
                }).ToList();

            var webOrders = web.DataTableEnumerable(@"
                    SELECT ORDER_NUMBER FROM TRANSACTIONS AS T WHERE
                    (Str_to_date(T.ORDER_DATE, '%Y%m%d %k:%i:%s') >= DATE_SUB(Now(),  INTERVAL 7 DAY))
                    AND (STR_TO_DATE(T.ORDER_DATE, '%Y%m%d %k:%i:%s') <= DATE_SUB(NOW(),  INTERVAL 1 HOUR))")
                .Select(o => new
                {
                    order = o[0].ToString().Trim()
                }).ToList();
            return (from w in webOrders
                    where !(from f in foamOrders
                            select f.order).Contains(w.order)
                    select w
                ).ToDataTable();
        }
    }
}

當你這樣做時,你的linq不再被推遲

ToDataTable();

在那時,它被拍攝為已完成並永遠拂去灰塵。

轉換它時,foamOrders和webOrders也是如此

ToList();

你可以把它做成一個查詢。 我沒有mySQL來檢查它。

關於延期執行:

方法.ToList()迭代IEnumerable檢索所有值並用該值填充新的List<T>對象。 所以在這一點上絕對不是延遲執行。

它最有可能與.ToDataTable();相同.ToDataTable();

PS但我建議:

  1. 使用自定義類型而不是匿名類型。
  2. 不要使用LINQ比較對象,因為它不是真正有效(linq正在做額外的工作)
  3. 您可以創建自定義MyComparer類(可能實現IComparer接口)和比較兩個實體的Compare<T1, T2>類的方法。 然后你可以創建另一個方法來比較兩組實體,例如T1[] CompareRange<T1,T2>(T1[] entities1, T2[] entities2)在循環中重用你的Compare方法並返回操作的結果

PS一些其他資源密集型操作可能會導致重大性能損失(如果您需要執行數千次操作):

  1. 枚舉器對象的使用( foreach循環或一些LINQ方法)

可能的解決方案:如果可能,嘗試使用for循環。

  1. 廣泛使用匿名方法(編譯器需要大量時間來編譯lambda表達式/運算符);

可能的解決方案:將lambda存儲在委托中(如Func<T1, T2>

如果它將來幫助任何人,我的新代碼將粘貼在下面。 現在快得多運行。 感謝大家的幫助,我了解到即使我的數據庫查詢的延遲執行被切斷,結果在我使用.ToList()后變為靜態,使用Linq來比較結果集合的效率非常低。 我轉而使用for循環。

private DataTable GetData()
    {
        //Needed to have both connections open in order to preserve the scope of var foamOrders and var webOrders, which are both needed in order to perform the comparison.
        using (var foam = Databases.Foam(isDebug))
        {
            using (MySqlConnection web = new MySqlConnection(Databases.ConnectionStrings.Web(isDebug)))
            {
                var foamOrders = foam.DataTableEnumerable(@"
            SELECT foreignID
            FROM   Orders
            WHERE  order_id NOT LIKE 'R35%'
            AND originpartner_code = 'VN000011'
            AND orderDate > Getdate() - 7 ")
                                     .Select(o => new
                                     {
                                         order = o[0].ToString()
                                                     .Trim()
                                     }).ToList();


                var webOrders = web.DataTableEnumerable(@"
            SELECT ORDER_NUMBER FROM transactions AS T WHERE
                                                (Str_to_date(T.ORDER_DATE, '%Y%m%d %k:%i:%s') >= DATE_SUB(Now(),  INTERVAL 7 DAY))
                                                AND (STR_TO_DATE(T.ORDER_DATE, '%Y%m%d %k:%i:%s') <= DATE_SUB(NOW(),  INTERVAL 1 HOUR))
                                                 ", 300)
                            .Select(o => new
                            {
                                order = o[0].ToString()
                                            .Trim()

                            }).ToList();


                List<OrderNumber> on = new List<OrderNumber>();

                foreach (var w in webOrders)
                {
                    if (!foamOrders.Contains(w))
                    {
                        OrderNumber o = new OrderNumber();
                        o.orderNumber = w.order;
                        on.Add(o);
                    }
                }

                return on.ToDataTable();

            }
        }


    }


    public class OrderNumber
    {
        public string orderNumber { get; set; }
    }


 }

暫無
暫無

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

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