2013-02-13 63 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