1

我有两个函数,每个函数都返回相同的对象列表。但是,使用 TSQL 的比使用实体框架的要快得多,我不明白为什么一个会比另一个快。是否可以修改我的 EF 函数以与 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;            
    }

英法:

            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;
        }
    }
4

2 回答 2

0

当然,执行 EF 将比普通的旧 SQL 查询花费更长的时间,而且您几乎无能为力(除了编写您可以编写的最优化的 LINQ 查询)。

原因很简单。运行直接 SQL 命令只会发回数据,没有任何麻烦,也不会大惊小怪,等待您进行数据操作以使其与您想要的任何数据结构完美匹配。运行另一方面,EF 意味着它不仅运行 SQL 命令,而且还为您将数据处理成您可以立即操作的对象。通过 ADO.NET 并将数据自动转换为对象的额外操作意味着这将比仅执行普通 SQL 查询花费更长的时间。

然而,在硬币的另一面,EF 确实提供了一种非常好的和简单的方法来调试和解决特定查询/函数可能遇到的任何问题(比如抛出的任何异常)。

于 2013-02-13T20:34:22.800 回答
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表单的功能调用,但无论哪种方式都是正确的。

于 2013-02-13T22:08:25.160 回答