1

それぞれが同じオブジェクトのリストを返す 2 つの関数があります。しかし、TSQL を使用するものは Entity Framework を使用するものよりもはるかに高速であり、一方が他方よりも高速である理由がわかりません。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;            
    }

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;
        }
    }
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();

これは、select から新しいオブジェクトを生成する「正しい」方法です。関心のあるデータのみを取得し、それをオブジェクトに変換してから、あるオブジェクトから別のオブジェクトに再度変換するのではなく、オブジェクトに直接配置します。

注: 私はfrom/selectフォームへの関数呼び出しを好みますが、どちらの方法でも正しいでしょう。

于 2013-02-13T22:08:25.160 に答える