iT邦幫忙

0

詢問下,AsEnumerable()和ToList(),兩個做法的效能

//AsEnumerable 的作法
var dt = (from t1 in db.AAA
          from t2 in db.BBB
          from t3 in db.CCC
         where t1.AAA_NAME == ...
        select new
     {
          DataColumn1 = t1.AAA_PK,
          DataColumn2 = t2.BBB_PK,
          DataColumn3 = t3.CCC_PK,
          ......
          DataColumn17 = t1.AAA_MOOD,
          DataColumn18 = t1.AAA_REMARKS,

      }).AsEnumerable()
      .Select(LoopRow => new
      {
          LoopRow.DataColumn1,
          ......
          DataColumn17 = (XXXCombo.GetSYSCODE(XXX).FirstOrDefault(t3 => t3.Selected) ?? new SelectListItem { }).Text,
          LoopRow.DataColumn18,
          DataColumn19 = database.DDD
                      .Where(t => t.AAA_FK == LoopRow.DataColumn1
                               && t.bDDD_CANCEL == false
                               && t.iDDD_TYPE == 1)
                      .Select(t =>
          string.Join("、",t.cDDD_NAME + (t.cDDD_CODE == "Z" && t.cDDD_OTHER != "" ? (":" + t.cDDD_OTHER) : "")
       ).AsEnumerable())
       });
       
//ToList 的作法
var dt1 = (from t1 in db.AAA
          from t2 in db.BBB
          from t3 in db.CCC
         where t1.AAA_NAME == ...
        select new
     {
          DataColumn1 = t1.AAA_PK,
          DataColumn2 = t2.BBB_PK,
          DataColumn3 = t3.CCC_PK,
          ......
          DataColumn17 = t1.AAA_MOOD,
          DataColumn18 = t1.AAA_REMARKS,

      }).ToList();
      var dtNew = XXX.GetRptTable(200);
      foreach (var LoopRow in dt1)
      {
      DataRow NewRow = dtNew.NewRow();
      NewRow["DataColumn1"] = LoopRow.DataColumn1;
      ......
      NewRow["DataColumn17"] = (XXXCombo.GetSYSCODE(XXX).FirstOrDefault(t3 => t3.Selected) ?? new SelectListItem { }).Text;
      NewRow["DataColumn18"] = LoopRow.DataColumn18;
      string sDDD_NAME = string.Empty;
      var dt2 = database.DDD.Where(t => t.AAA_FK == LoopRow.DataColumn1
                                      && t.bDDD_CANCEL == false
                                      && t.iDDD_TYPE == 1)
                              .Select(t => new { t.cDDD_NAME, t.cDDD_CODE, t.cDDD_OTHER }).ToList();
               foreach (var LoopRow2 in dt2)
               {
                 sDDD_NAME += "、" + LoopRow2.cDDD_NAME;
                 if (LoopRow2.cDDD_CODE == "Z")
                 {
                   sDDD_NAME += string.IsNullOrEmpty(LoopRow2.cDDD_OTHER) ? "" : $":{LoopRow2.cDDD_OTHER}";
                        }
                    }

                    NewRow["DataColumn19"] = sDDD_NAME.TrimStart('、');
                    dtNew.Rows.Add(NewRow);
                }

以上為兩做法的程式碼,想問這兩個效能的比較,另外有省略大部分程式碼,以供閱讀。

2 個回答

2
I code so I am
iT邦研究生 5 級 ‧ 2019-08-31 21:18:59

LINQ 不會馬上執行,它會等到最後或遇到ToList()才會實際轉為SQL執行,所以,過早執行ToList(),會使轉換的 SQL 變得沒有效率,例如,你分段使用 select、where、order,如果每一段都使用 ToList(),實際執行的結果如下:

  1. select 所有資料至 list。
  2. 由 list 篩選資料至新的 list。
  3. 由新的 list 再排序。

當然執行效率就變差了。

優悠 iT邦新手 4 級 ‧ 2019-09-02 09:06:27 檢舉

您好,您說的我都知道,我只是想問我上述的那兩個做法,它們實際跑的效能如何,謝謝。

我猜第一種作法比較好。您可以參閱這篇文章( blog.usejournal.com/enumeration-in-net-d5674921512e )他其中有一段有提到:

Now imagine that you want to apply LINQ operators to the query result. Don’t use ToList() or ToArray(). Use AsEnumerable() instead. It will keep the lazy evaluation, without memory usage.

原文的這段說明,底下有附一個小範例,請您參考一下。

0
mis2000lab
iT邦好手 1 級 ‧ 2019-10-04 14:33:17

我猜第一種作法比較好。您可以參閱這篇文章( blog.usejournal.com/enumeration-in-net-d5674921512e )他其中有一段有提到:

Now imagine that you want to apply LINQ operators to the query result. Don’t use ToList() or ToArray(). Use AsEnumerable() instead. It will keep the lazy evaluation, without memory usage.

原文的這段說明,底下有附一個小範例,請您參考一下。

優悠 iT邦新手 4 級 ‧ 2019-10-06 07:38:02 檢舉

您好,感謝您的回答,我目前的做法,是使用第二種(ToList+foreach),因為foreach能看到哪個欄位錯誤,第一作法發生錯誤時,較難查詢。

我要發表回答

立即登入回答