2013-02-13 66 views
1

我有兩個函數,每個函數返回相同的對象列表。但是,使用TSQL的實例比使用Entity Framework的實例要快得多,我不明白爲什麼會比另一個更快。是否有可能修改我的EF函數以像TSQL那樣快地工作?使用基於實體框架的函數基於TSQL轉換函數

任何幫助將不勝感激。我的代碼如下:

TSQL:

public static List<ChartHist> ListHistory_PureSQL() 
    { 
     List<DataRow> listDataRow = null; 
     string srtQry = @"Select LoginHistoryID, 
            LoginDuration as LoginDuration_Pass, 
            0 as LoginDuration_Fail, 
            LoginDateTime, 
            LoginLocationID, 
            LoginUserEmailID, 
            LoginApplicationID, 
            LoginEnvironmentID, 
            ScriptFrequency, 
            LoginStatus, 
            Reason 
          From LoginHistory 
          Where LoginStatus = 'Pass' 
          UNION 
          Select LoginHistoryID, 
            0 as LoginDuration_Pass, 
            LoginDuration as LoginDuration_Fail, 
            LoginDateTime, 
            LoginLocationID, 
            LoginUserEmailID, 
            LoginApplicationID, 
            LoginEnvironmentID, 
            ScriptFrequency, 
            LoginStatus, 
            Reason 
          From LoginHistory 
          Where LoginStatus = 'Fail'"; 

     using (SqlConnection conn = new SqlConnection(Settings.ConnectionString)) 
     { 
      using (SqlCommand objCommand = new SqlCommand(srtQry, conn)) 
      { 
       objCommand.CommandType = CommandType.Text; 
       DataTable dt = new DataTable(); 
       SqlDataAdapter adp = new SqlDataAdapter(objCommand); 
       conn.Open(); 
       adp.Fill(dt); 
       if (dt != null) 
       { 
        listDataRow = dt.AsEnumerable().ToList(); 
       } 
      } 
     } 


     var listChartHist = (from p in listDataRow 
         select new ChartHist 
         { 
          LoginHistoryID = p.Field<Int32>("LoginHistoryID"), 
          LoginDuration_Pass = p.Field<Int32>("LoginDuration_Pass"), 
          LoginDuration_Fail = p.Field<Int32>("LoginDuration_Fail"), 
          LoginDateTime = p.Field<DateTime>("LoginDateTime"), 
          LoginLocationID = p.Field<Int32>("LoginLocationID"), 
          LoginUserEmailID = p.Field<Int32>("LoginUserEmailID"), 
          LoginApplicationID = p.Field<Int32>("LoginApplicationID"), 
          LoginEnvironmentID = p.Field<Int32>("LoginEnvironmentID"), 
          ScriptFrequency = p.Field<Int32>("ScriptFrequency"), 
          LoginStatus = p.Field<String>("LoginStatus"), 
          Reason = p.Field<String>("Reason") 
         }).ToList(); 

     return listChartHist;    
    } 

EF:

  public static List<ChartHist> ListHistory() 
    { 
     using (var db = new LatencyDBContext()) 
     { 
      var loginHist = (from hist in db.LoginHistories 
          select new { LoginHistory = hist }).ToList(); 


      //PUT LOGIN HISTORY RECORDS INTO A LOCAL LIST 
      var listHistory = new List<ChartHist>(); 
      foreach (var item in loginHist) 
      { 
       var localHistData = new ChartHist(); 

       localHistData.LoginHistoryID = item.LoginHistory.LoginHistoryID; 

       //split up the duration for pass and fail values 
       if (item.LoginHistory.LoginStatus.ToUpper() == "PASS") 
       { 
        localHistData.LoginDuration_Pass = Convert.ToDouble(item.LoginHistory.LoginDuration); 
        localHistData.LoginDuration_Fail = 0; 
       } 
       else if (item.LoginHistory.LoginStatus.ToUpper() == "FAIL") 
       { 
        localHistData.LoginDuration_Pass = 0; 
        localHistData.LoginDuration_Fail = Convert.ToDouble(item.LoginHistory.LoginDuration); 
       } 

       localHistData.LoginDateTime = item.LoginHistory.LoginDateTime; 
       localHistData.LoginLocationID = item.LoginHistory.LoginLocationID; 
       localHistData.LoginUserEmailID = item.LoginHistory.LoginUserEmailID; 
       localHistData.LoginApplicationID = item.LoginHistory.LoginApplicationID; 
       localHistData.LoginEnvironmentID = item.LoginHistory.LoginEnvironmentID; 
       localHistData.LoginStatus = item.LoginHistory.LoginStatus; 
       localHistData.Reason = item.LoginHistory.Reason; 
       localHistData.ScriptFrequency = item.LoginHistory.ScriptFrequency; 

       listHistory.Add(localHistData); 
      } 

      return listHistory; 
     } 
    } 
+0

你的EF查詢生成了什麼SQL呢? – millimoose 2013-02-13 20:31:42

+0

SELECT [Extent1] [LoginHistoryID] AS [LoginHistoryID], [Extent1] [LoginDuration] AS [LoginDuration], [Extent1] [LoginDateTime] AS [LoginDateTime], [Extent1] [LoginLocationID] AS [LoginLocationID], [Extent1] [LoginUserEmailID] AS [LoginUserEmailID], [Extent1] [LoginApplicationID] AS [LoginApplicationID], [Extent1] [LoginEnvironmentID] AS [LoginEnvironmentID], [Extent1]。[ScriptFrequency ] AS [ScriptFrequency], [Extent1]。[LoginStatus] AS [LoginStatus], [Extent1]。[原因] AS [Reason] FROM [dbo]。[LoginHistory] ​​AS [Extent1] – ADH 2013-02-13 20:40:25

+0

嘗試刪除'。 ToList();'從EF版本的'loginHist'中看看這是否有所作爲。 – Bobson 2013-02-13 20:58:07

回答

0

當然EF將需要更長的時間比普通的舊SQL查詢來執行,並有很少的,你可以做關於它(除了編寫最適合您的LINQ查詢)。

有一個非常簡單的原因,爲什麼這樣。運行一個直接的SQL命令只會發回數據,沒有任何麻煩,也沒有附加任何東西,等待你做數據處理,以使它達到適合你想要的任何數據結構的程度。運行另一方面,EF意味着它不僅可以運行SQL命令,還可以將數據轉換爲可以立即處理的對象。通過ADO.NET並將數據自動轉換爲對象的額外操作意味着它將花費更多的時間,而不僅僅是執行純SQL查詢。然而,在這個硬幣的另一面,EF提供了一個非常好的和簡單的方法來調試和解決你可能從特定的查詢/功能(如拋出的任何異常)中可能遇到的任何問題。

+0

感謝您的信息。我將刪除我的代碼的大部分EF方面並編寫一個非常好的T-SQL語句。 – ADH 2013-02-13 21:03:36

+0

@ IronMan84 - 我正在寫我的理由,但我一直在修改它。我覺得你在這裏歪曲EF,但我很難明確地說出爲什麼。EF本質上較慢,但本質上不顯着*較慢 – Bobson 2013-02-13 22:14:44

+0

我沒有說它顯着較慢(儘管可能是因爲您的LINQ查詢不是最佳的)。我只是回答爲什麼它通常會變慢。 – IronMan84 2013-02-13 22:17:30

0

我不能性能測試這一點,但嘗試這種解決方案,您刪除EF完全代替之前:

var loginHist = db.LoginHistories.Where(item => item.LoginStatus.ToUpper() == "PASS" || item.LoginStatus.ToUpper() == "FAIL") 
        .Select(item => new ChartHist() 
        { 

        LoginHistoryID = item.LoginHistoryID, 
        LoginDuration_Pass = item.LoginStatus.ToUpper() == "PASS" ? Convert.ToDouble(item.LoginDuration) : 0, 
        LoginDuration_Fail = item.LoginStatus.ToUpper() == "FAIL" ? Convert.ToDouble(item.LoginDuration) : 0, 

        LoginDateTime = item.LoginDateTime, 
        LoginLocationID = item.LoginLocationID, 
        LoginUserEmailID = item.LoginUserEmailID, 
        LoginApplicationID = item.LoginApplicationID, 
        LoginEnvironmentID = item.LoginEnvironmentID, 
        LoginStatus = item.LoginStatus, 
        Reason = item.Reason, 
        ScriptFrequency = item.ScriptFrequency, 

        }); 
return loginHist.ToList(); 

這是「正確」的方式來填充從選擇一個新的對象。它只會檢索您關心的數據,並將其直接放入對象中,而不是將其轉換爲對象,然後再將它從另一個對象轉換爲再次

注意:我更喜歡對from/select表單進行功能調用,但這種方式無論如何都是正確的。

+0

這是很好的代碼。我將用它更新我的其他存儲庫函數,但我已經用T-Sql替換了LoginHistories查詢,它工作得非常好,速度也更快。 – ADH 2013-02-14 21:51:39