<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
        

      疑難雜癥——關于EntityFramework的SqlQuery方法的執行效率差異的探討

      前言:最近項目上面遇到一個問題,在Code First模式里面使用EntityFramework的SqlQuery()方法查詢非常慢,一條數據查詢出來需要10秒以上的時間,可是將sql語句放在plsql里面執行,查詢時間基本可以忽略不計。折騰了半天時間,仍然找不到原因。最后通過對比和原始Ado的查詢方式的差異找到原因,今天將此記錄下。

      本文原創地址:http://www.rzrgm.cn/landeanfen/p/8392498.html

      一、問題描述

      其實問題很簡單,上面前言已經描述過。就是一個多表的聯合查詢,沒有什么特殊的語法。大致代碼如下:(PS:不要問為什么用了EF還要使用sql語句,你就當這是個梗!)

      通用的sql語句查詢方法

           public IEnumerable<TEntity> SqlQuery<TEntity>(string sql, params object[] parameters)
              {
                  return this._dbContext.Database.SqlQuery<TEntity>(sql, parameters).ToArray();
              }

      然后在外層調用這個方法

       var sql = @"select * from (
                      select ax.*,rownum as rnum from (
                      select o.* from order o
                      left join ordertt a on o.id=a.orderid
                      left join orderdd d on o.id=d.orderid
                      left join orderstation ts on d.station = ts.id
                      left join ordermodel m on o.materialid=m.id
                      where 1=1  and o.status = 30
                      order by ts.no,tw.seq
                      ) ax ) t 
                       where t.rnum>0 and t.rnum <=15";
      
                      var result = SqlQuery(sql);

      然后查詢,每次得到的結果都是一條記錄,但是卻需要10秒以上,可能你不相信,但這是真的!

      問題就這么個問題,沒辦法,出現了問題就要想辦法解決。

      二、找到解決方案

      我們將SqlQuery<T>()方法轉到定義,最終發現它是EntityFramework.dll里面的方法。

      既然轉到定義已經找不到任何突破口,那我們常規的做法就只有對比了。然后博主在本地定義了一個對比的例子。

      原始組:EF的SqlQuery()方法

           //EF查詢方法
              private static IEnumerable<TestModel> EFSqlQuery(DbContext db, string sql)
              {
                  return db.Database.SqlQuery<TestModel>(sql).ToArray();
              }

      對比照:Ado的查詢方法

           //ADO的查詢方法
              private static IEnumerable<TestModel> AdoSqlQuery(DbContext db, string sql)
              {
                  DataTable dt = ExecuteDataTable(db, sql);
                  var ms = GetListByDataTable<TestModel>(dt);
                  return ms;
              }
      //DataTable轉List<T>公共的方法
              private static DataTable ExecuteDataTable(DbContext db, string sql, params System.Data.Common.DbParameter[] parameters)
              {
                  DataTable dt = new DataTable();
      
                  var conn = db.Database.Connection;
      
                  conn.Open();
                  using (var cmd = db.Database.Connection.CreateCommand())
                  {
                      foreach (var p in parameters) cmd.Parameters.Add(p);
      
                      cmd.CommandText = sql;
                      dt.Load(cmd.ExecuteReader());
                  }
                  conn.Close();
      
                  return dt;
              }
      
              private static List<T> GetListByDataTable<T>(DataTable dt) where T : class, new()//這個意思是一個約束,約定泛型T必須要有一個無參數的構造函數
              {
                  List<T> lstResult = new List<T>();
                  if (dt.Rows.Count <= 0 || dt == null)
                  {
                      return lstResult;
                  }
                  //反射這個類得到類的類型。
                  Type t = typeof(T);
                  //聲明一個泛型類對象
                  T oT;
                  //得到這個類的所有的屬性
                  PropertyInfo[] lstPropertyInfo = t.GetProperties();
                  foreach (DataRow dr in dt.Rows)
                  {
                      //一個DataRow對應一個泛型對象
                      oT = new T();
                      //遍歷所有的屬性
                      for (var i = 0; i < lstPropertyInfo.Length; i++)
                      {
                          //得到屬性名
                          string strPropertyValue = lstPropertyInfo[i].Name;
                          //只有表格的列包含對應的屬性
                          if (dt.Columns.Contains(strPropertyValue))
                          {
                              object oValue = Convert.IsDBNull(dr[strPropertyValue]) ? default(T) : GetTypeDefaultValue(lstPropertyInfo[i].PropertyType.ToString(), dr[strPropertyValue]);
                              //給對應的屬性賦值
                              lstPropertyInfo[i].SetValue(oT, oValue, null);
                          }
                      }
                      lstResult.Add(oT);
                  }
                  return lstResult;
              }
      
              private static object GetTypeDefaultValue(string strTypeName, object oValue)
              {
                  switch (strTypeName)
                  {
                      case "System.String":
                          return oValue.ToString();
                      case "System.Int16":
                      case "System.Nullable`1[System.Int16]":
                          return Convert.ToInt16(oValue);
                      case "System.UInt16":
                      case "System.Nullable`1[System.UInt16]":
                          return Convert.ToUInt16(oValue);
                      case "System.Int32":
                      case "System.Nullable`1[System.Int32]":
                          return Convert.ToInt32(oValue);
                      case "System.UInt32":
                      case "System.Nullable`1[System.UInt32]":
                          return Convert.ToUInt32(oValue);
                      case "System.Int64":
                      case "System.Nullable`1[System.Int64]":
                          return Convert.ToInt64(oValue);
                      case "System.UInt64":
                      case "System.Nullable`1[System.UInt64]":
                          return Convert.ToUInt64(oValue);
                      case "System.Single":
                      case "System.Nullable`1[System.Single]":
                          return Convert.ToSingle(oValue);
                      case "System.Decimal":
                      case "System.Nullable`1[System.Decimal]":
                          return Convert.ToDecimal(oValue);
                      case "System.Double":
                      case "System.Nullable`1[System.Double]":
                          return Convert.ToDouble(oValue);
                      case "System.Boolean":
                      case "System.Nullable`1[System.Boolean]":
                          return Convert.ToBoolean(oValue);
                      case "System.DateTime":
                      case "System.Nullable`1[System.DateTime]":
                          return Convert.ToDateTime(oValue);
                      case "System.SByte":
                      case "System.Nullable`1[System.SByte]":
                          return Convert.ToSByte(oValue);
                      case "System.Byte":
                      case "System.Nullable`1[System.Byte]":
                          return Convert.ToByte(oValue);
                      case "System.Char":
                      case "System.Nullable`1[System.Char]":
                          return Convert.ToChar(oValue);
                      case "System.Object":
                      case "System.Nullable`1[System.Object]":
                          return oValue;
                      case "System.Array":
                          return oValue as Array;
      
                      default:
                          return "";
                  }
              }
      GetListByDataTable

      然后在控制臺里面分別調用。

       private static void Main(string[] args)
              {
                  Stopwatch sw = new Stopwatch();
                  using (MesDbContext db = new MesDbContext())
                  {
                      var sql = @"select * from (
                      select ax.*,rownum as rnum from (
                      select o.* from order o
                      left join ordertt a on o.id=a.orderid
                      left join orderdd d on o.id=d.orderid
                      left join orderstation ts on d.station = ts.id
                      left join ordermodel m on o.materialid=m.id
                      where 1=1  and o.status = 30
                      order by ts.no,tw.seq
                      ) ax ) t 
                       where t.rnum>0 and t.rnum <=15";
                      //“預熱”
                      EFSqlQuery(db, sql);
      
                      sw.Start();
                      var result = EFSqlQuery(db, sql);
                      sw.Stop();
                      Console.WriteLine("使用EF里面的SqlQuery方法查詢得到" + result.Count() + "條記錄。總耗時" + sw.Elapsed);
      
                      //同樣也預熱一下
                      AdoSqlQuery(db, sql);
                      sw.Restart();
                      var result2 = AdoSqlQuery(db, sql);
                      sw.Stop();
                      Console.WriteLine("使用原始的Ado查詢得到" + result.Count() + "條記錄。總耗時" + sw.Elapsed);
      
                  }
              }

      得到結果:

      差別有多大大家可以自行腦補。

      原因分析

      既然結果差別這么大,而sql語句在plsql里面執行又如此快,那么問題自然而然轉到了對象序列化的身上了。也就是說這個SqlQuery()方法實際上可以分為兩個步驟:第一步是查詢得到DataTable之類的對象,然后第二步是將DataTable之類的對象轉換為List<T>,既然我們第一步沒有任何效率問題,那么問題肯定就在第二步上面了。

      解決方案

      既然初步判斷是對象轉換的問題,將TestModel這個對象轉到定義一看,我地個乖乖,一百來個屬性,于是更加堅信自己的分析是正確的。接下來,博主將這一百個字段減少到50個,再次執行發現效率提高了不少,基本在3秒左右,再減少到只剩20個字段,查詢時間基本在毫秒級別。原來真是反射賦值的效率問題啊。至于項目為什么會有100個字段的對象,博主也沒有想明白,或許真的需要吧!但是由此我們可以得出如下經驗:

      1、查詢的sql語句里面盡量不要用select * 這種語法,尤其是連表的時候,如果你用了select * ,那有時真的就傷不起了!

      2、如果確定實體里面真的有那么多字段有用(極端的情況),就不要用SqlQuery()了,而改用原生的Ado+DT轉List<T>的方式。

      三、意外的“環境問題”

      本來以為找到了原因了,正要下結論的時候。聽到另一個同事傳來了不同的聲音:騙紙,你的這個測試程序在我這里跑這么快,哪里有你說的10秒以上!去他那邊瞅了一眼,嚇我一跳,哪里有什么效率問題,簡直快得不要不要的!這就尷尬了,同樣的程序,在我這邊怎么這么慢呢?

      最后對比一圈下來,發現他那邊用的Visual Studio的版本是2017,而我這邊是2015。難道真是IDE的環境問題?博主不甘心,在本機裝了一個2017,運行程序,依然快得嚇人。而關掉2017,再用2015跑,同樣需要10秒左右,而且找到其他裝了VS 2013的電腦,用2013運行,依然需要10秒左右。好像2017以下的版本速度都會有一些影響。對比各個主要dll的版本,最終找不到任何不同。到這里,博主也沒有辦法了。如果哪位有解,感謝賜教!

      那就用2017唄,這是最后得出的結論!!!

      四、總結

      以上針對最近遇到的一個問題做了一些記錄。如果大家有不同的意見,歡迎交流和斧正!

      本文原創出處:http://www.rzrgm.cn/landeanfen/

      歡迎各位轉載,但是未經作者本人同意,轉載文章之后必須在文章頁面明顯位置給出作者和原文連接,否則保留追究法律責任的權利

      posted @ 2018-01-31 16:34  懶得安分  閱讀(6958)  評論(23)    收藏  舉報
      主站蜘蛛池模板: 国产精品无遮挡又爽又黄| 中文字幕亚洲人妻系列| 国产精品久久毛片| 国产精品中文第一字幕| 国产l精品国产亚洲区 | 诱人的老师hd中文字幕| 超碰成人人人做人人爽| 久久综合开心激情五月天| 国产在线中文字幕精品| 人妻夜夜爽天天爽三区丁香花| 91精品国产老熟女在线| 亚洲人成人无码网WWW电影首页| www国产成人免费观看视频| 奇米四色7777中文字幕| 国产乱码精品一区二区三| 人人做人人澡人人人爽| 97人人模人人爽人人少妇| 无码日韩精品一区二区三区免费| 无码丰满人妻熟妇区| 国产AV福利第一精品| 德兴市| 国产精品午夜福利免费看| 91精品国产午夜福利| 盖州市| 人妻熟妇乱又伦精品无码专区| 国产国拍亚洲精品永久软件| 秋霞人妻无码中文字幕| 一本色道久久综合亚洲精品不卡| 洱源县| 久久精品av国产一区二区| 午夜色无码大片在线观看免费| 亚洲男女羞羞无遮挡久久丫| 亚洲成av人片色午夜乱码| 精品视频在线观看免费观看| 亚洲欧美日韩成人综合一区| 久青草国产在视频在线观看| 国产性色的免费视频网站| 91色老久久精品偷偷性色| 一本一本久久a久久综合精品| 中文字幕丰满伦子无码ab| 久久亚洲精品国产精品尤物|