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

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

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

      性能優(yōu)化知多少

      1. 引言

      最近一段時間,系統(tǒng)新版本要發(fā)布,在beta客戶測試期間,暴露了很多問題,除了一些業(yè)務和異常問題外,其他都集中在性能上。有幸接觸到這些性能調(diào)優(yōu)的機會,當然要學習總結(jié)了。

      性能優(yōu)化是一個老生常談的問題了,典型的性能問題如頁面響應慢、接口超時,服務器負載高、并發(fā)數(shù)低,數(shù)據(jù)庫頻繁死鎖等。而造成性能問題又有很多種,比如磁盤I/O、內(nèi)存、網(wǎng)絡(luò)、算法、大數(shù)據(jù)量等等。我們可以大致把性能問題分為四個層次:代碼層次、數(shù)據(jù)庫層次、算法層次、架構(gòu)層次。
      所以下面我會結(jié)合實際性能優(yōu)化案例,和大家分享下性能調(diào)優(yōu)的工具、方法和技巧。

      2. 先說心態(tài)

      說到性能問題,你可能首先就想到的是麻煩或者頭大,因為一般性能問題都比較緊急,輕則影響客戶體驗,重則宕機導致財務損失,而且性能問題比較隱蔽,不易發(fā)現(xiàn)。因此一時間無從下手,而這時我們就很容易從心底開始去排斥它,不愿接這燙手的山芋。

      而恰巧,性能調(diào)優(yōu)是體現(xiàn)程序員水平的一個重要指標。

      因為處理bug、崩潰、調(diào)優(yōu)、入侵等突發(fā)事件比編程本身更能體現(xiàn)平庸程序員與理想程序員的差距。當面對一個未知的問題時,如何定位復雜條件下的核心問題、如何抽絲剝繭地分析問題的潛在原因、如何排除干擾還原一個最小的可驗證場景、如何抓住關(guān)鍵數(shù)據(jù)驗證自己的猜測與實驗,都是體現(xiàn)程序員思考力的最好場景。是的,在衡量理想程序員的標準上,思考力比經(jīng)驗更加重要。

      所以,若你不甘平庸,請擁抱性能調(diào)優(yōu)的每一個機會。當你擁有一個正確的心態(tài),你所面對的性能問題就已經(jīng)解決了一半。

      3. 再說技巧

      拿到一個性能問題,不要忙著先上工具,先了解問題出現(xiàn)的背景,問題的嚴重程度。然后大致根據(jù)自己的經(jīng)驗積累作出預估。比如客戶來了個性能問題說系統(tǒng)宕機了,已經(jīng)造成資金損失了。這種涉及到錢的問題,大家都比較敏感,根據(jù)自己的level,決定是否要接這個鍋。這不是逃避,而是自知之明。

      了解問題背景之后,下一步就來嘗試問題重現(xiàn)。如果在測試環(huán)境能夠重現(xiàn),那這種問題就很好跟蹤分析。如果問題不能穩(wěn)定重現(xiàn)或僅能在生產(chǎn)環(huán)境重現(xiàn),那問題就相對比較棘手,這時要立刻收集現(xiàn)場證據(jù),包括但不限于抓dump、收集應用程序以及系統(tǒng)日志、關(guān)注CPU內(nèi)存情況、數(shù)據(jù)庫備份等等,之后不妨再嘗試重現(xiàn),比如恢復客戶數(shù)據(jù)庫到測試環(huán)境重現(xiàn)。

      不管問題能否重現(xiàn),下一步,我們就要大致對問題進行分類,是代碼層次的業(yè)務邏輯問題還是數(shù)據(jù)庫層次的操作耗時問題,又或是系統(tǒng)架構(gòu)的吞吐量問題。那如何確定呢?而我傾向于先從數(shù)據(jù)庫動手。我的習慣做法是,使用數(shù)據(jù)庫監(jiān)控工具,先跟蹤下Sql耗時情況。如果監(jiān)控到耗時較長的SQL語句,那基本上就是數(shù)據(jù)庫層次的問題,否則就是代碼層次。若為代碼層次,再研究完代碼后,再細化為算法或架構(gòu)層次問題。

      確定問題種類后,是時候上工具來精準定位問題點了:

      精準定位問題點后,就是著手優(yōu)化了。相信到這一步,就是優(yōu)化策略的選擇了,這里就不展開了。

      優(yōu)化后,最后當然要進行測試了,畢竟優(yōu)化了多少,我們也要做到心里有譜才行。

      以上啰啰嗦嗦有點多,下面我們直接上案例。

      4. 案例分享

      下面就分享下我針對代碼層面、數(shù)據(jù)庫層面和算法層面的優(yōu)化案例。

      4.1. SQL優(yōu)化案例

      案例1:客戶反饋某結(jié)算報表統(tǒng)計十天內(nèi)的數(shù)據(jù)耗時10mins左右。

      由于前幾天剛學會用RedGate的分析工具,拿到這個問題,本地嘗試重現(xiàn)后,就直接想使用工具分析。然而,這工具在使用webdev模式起站點時,總是報錯,而當時時一根筋,老是想解決這個工具的報錯問題。結(jié)果,白白搞了半天也沒搞定。最后不得已放棄工具,轉(zhuǎn)而選擇使用sql server profiler去監(jiān)控sql語句耗時。一跟蹤不要緊,問題就直接暴露了,整個全屏的重復sql語句,如下圖。

      Sql Profiler監(jiān)控結(jié)果

      這下問題就很明顯了,八成是代碼在循環(huán)拼接sql執(zhí)行語句。根據(jù)抓取到sql關(guān)鍵字往代碼中去搜索,果然如此。

      #region更新三張表數(shù)據(jù)結(jié)合的中間臨時表數(shù)據(jù),有上游單據(jù)的直接調(diào)撥單分多次下推時,只計算一次的調(diào)撥數(shù)量和價稅合計
      string sSql = string.Format(@
      "SELECT FENTRYID FROM {0} GROUP BY FENTRYID HAVING COUNT(FENTRYID) > 1", sJoinDataTempTable);
      using(IDataReader reader = DBUtils.ExecuteReader(this.Context, sSql)) {
          while (reader.Read()) {
              sbSql.AppendFormat(@"
      UPDATE {0} SET FDIRECTQTY = 0,FALLAMOUNT = 0 
      WHERE FSEQ NOT IN (
      SELECT TOP 1 FSEQ FROM {0} WHERE FENTRYID = {1}) AND FENTRYID = ({1});"
      , sJoinDataTempTable, Convert.ToInt32(reader["FENTRYID"]));
              listSqlObj.Add(new SqlObject(sbSql.ToString(), new List < SqlParam > ()));
              sbSql.Clear();
          }
      }
      #endregion
      

      看到這段代碼,咱先不評判這段代碼的優(yōu)劣,因為畢竟代碼注釋清晰,省了我們理清業(yè)務的功夫。這段sql主要是想做去重處理,很顯然選用了錯誤的方案。改后代碼如下:

      string sqlMerge = string.Format(@"
      merge into {0} t1
      using(
      select min(Fseq) fseq,Fentryid from {0} t2 group by fentryid
      ) t3 on (t1.fentryid = t3.fentryid and t1.fseq <> t3.fseq)
      when matched then
      update set t1.FDIRECTQTY = 0, t1.FALLAMOUNT = 0
      ", sJoinDataTempTable);
      
      listSqlObj.Add(new SqlObject(sqlMerge, new List < SqlParam > ()));
      sbSql.Clear();
      

      改后測試相同數(shù)據(jù)量,耗時由10mins降到10s左右。

      4.2. 代碼優(yōu)化案例

      案例2:客戶反饋銷售訂單100條分錄行,保存進行可發(fā)量校驗時,耗時7mins左右。

      拿到這個問題后,本地重現(xiàn)后,監(jiān)控sql耗時沒有異常,那就著重分析代碼了。因為可發(fā)量校驗的業(yè)務邏輯極其復雜,又加上又直接再一個類文件實現(xiàn)該功能,3500+行的代碼,加上零星注釋,真是讓人避之不及。逃避不是辦法,還是上工具分析一把。
      這次我選用的時VS自帶的Performance Profiler,開發(fā)環(huán)境下極其強大的性能調(diào)優(yōu)工具。針對我們當前案例,我們僅需要跟蹤指定服務對應的dll即可,使用步驟如下:

      1. Analyze-->Profiler-->New Performance Session
      2. 打開Performance Explorer
      3. 找到新添加的Performance Session,右鍵Targets,然后選擇Add Target Binary,添加要跟蹤的dll文件即可
      4. 將應用跑起來
      5. 選中Performance Session,右鍵Attach對應進程即可跟蹤分析性能了
      6. 在跟蹤過程中,可隨時暫停跟蹤和停止跟蹤

      圖示步驟

      跟蹤結(jié)束后本案例跟蹤到的采樣結(jié)果如下圖:

      VS Performance Profiler分析報告

      同時Performance Profiler也給出了問題的建議,如下圖:
      VS Performance Profiler分析提示

      其中第1、4條大致說明程序I/O消耗大,第一代的GC上存在未及時釋放的垃圾占比過高。而根據(jù)上圖的采樣結(jié)果,我們可以直接看出是由于再代碼中頻繁操作DataTable引起的性能瓶頸。走讀代碼發(fā)現(xiàn)的確如此,所有的數(shù)量統(tǒng)計都是在代碼中循環(huán)遍歷DataTable進行處理的。而最終的優(yōu)化策略,就相當于一次大的重構(gòu),將所有代碼中通過遍歷DataTable的計算邏輯全部挪到SQL中去做。由于代碼過多,就不再放出。

      案例3:客戶反饋批量引入1000張訂單,耗時40mins左右,且容易中斷。

      同樣,我們還是先嘗試本地重寫。經(jīng)測試批量引入101張單據(jù),就耗時5mins左右。下一步打開Sql監(jiān)控工具也未發(fā)現(xiàn)耗時語句。但考慮到是批量導入操作,雖然單個耗時不多,但乘以100這個基數(shù),就明顯了。下面我們就使用RedGate的Ants Performance Profiler跟蹤一下。

      該工具比較直觀,可以同時監(jiān)控代碼和SQL執(zhí)行情況。第一步,New Profiler Session,第二步進行設(shè)置,如下圖。根據(jù)自己的應用程序類別,選擇相應的跟蹤方式。

      跟蹤設(shè)置

      針對這個問題,我們跟蹤到的調(diào)用堆棧和SQL耗時結(jié)果如下圖:

      調(diào)用堆棧監(jiān)控結(jié)果

      SQL監(jiān)控結(jié)果

      首先從調(diào)用堆棧中的Hit Count,我們可以首先看出它是一個批量過程,因為入口函數(shù)僅調(diào)用一次;第二個我們可以代碼中是循環(huán)處理每一個單據(jù),因為Hit Count與我們批量引入的單據(jù)數(shù)量相符;第三個,突然來了個10201,如果有一定的數(shù)字敏感性的話,這次性能問題的原因就被你找到了。這里就不賣關(guān)子了,101 x 101 = 10201。
      是不是明白了什么,存在循環(huán)嵌套循環(huán)的情況。我們走讀代碼確定一下:

      //Save.cs
      public override void EndOperationTransaction(EndOperationTransactionArgs e) {
          //省略其他代碼
          foreach(DynamicObject dyItem in e.DataEntitys) {
              //反寫收款單
              WriteBackReceiveBill wb = new WriteBackReceiveBill();
              wb.WriteBackForSave(e, this.Context);
          }
      }
      
      //WriteBackReceiveBill .cs
      public void WriteBackForSave(EndOperationTransactionArgs e, Context contx) {
          //省略其他代碼:
          foreach(DynamicObject item in e.DataEntitys) {
              //do something 
          }
      }
      

      好嘛,外層套了一個空循環(huán)卻什么也沒做。修改就很簡單了,刪除無效外層循環(huán)即可。

      4.3. 算法優(yōu)化案例

      案例4:某全流程跟蹤報表超時。

      這個報表是用來跟蹤所有單據(jù)從下單到出庫的業(yè)務流程數(shù)據(jù)流轉(zhuǎn)情況。而所有的流程數(shù)據(jù)都是按照樹形結(jié)果存儲在數(shù)據(jù)庫表中的,類似這樣:

      流程樹表

      圖中的流程為:
      銷售合同-->銷售訂單-->發(fā)貨通知單-->銷售出庫單

      為了構(gòu)造流程圖,之前的處理方法是把流程數(shù)據(jù)取回來,通過代碼構(gòu)造流程圖。這也就是性能差的原因。

      而針對這種情況,就是考驗我們平時經(jīng)驗積累了。對于樹形結(jié)構(gòu)的表,我們也是可以通過SQL來進行直接查詢的,這就要用到了SQL Server的CTE語法來進行遞歸查詢。關(guān)于遞歸查詢,可參考我這篇文章:SQL遞歸查詢知多少。這里就不展開了。

      5.總結(jié)

      性能調(diào)優(yōu)是一個循序漸進的過程,不可能一蹴而就,重在平時的點滴積累。關(guān)于工具的選擇和使用,本文并未展開,也希望讀者也不要糾結(jié)與此。當你真正想解決一個問題的時候,相信工具的使用是難不住你的。

      最后就大致總結(jié)下我的調(diào)優(yōu)思路:

      1. 調(diào)整心態(tài),積極應對
      2. 了解性能背景, 收集證據(jù), 嘗試重現(xiàn)
      3. 問題分類,先監(jiān)控SQL耗時,大致確定是SQL或是代碼層次原因
      4. 使用性能分析工具,確定問題點
      5. 調(diào)優(yōu)測試
      posted @ 2017-07-03 08:15  「圣杰」  閱讀(20537)  評論(43)    收藏  舉報
      主站蜘蛛池模板: 91精品国产吴梦梦在线观看永久| 久久视频这里只精品| 激情综合网激情国产av| 色综合久久久久综合体桃花网| 大陆一级毛片免费播放| 国产熟睡乱子伦视频在线播放| 亚洲伊人久久综合影院| 武隆县| 中文字幕少妇人妻精品| 国产av激情无码久久| 蜜臀av一区二区三区在线| 国产一区二区日韩在线| 亚洲精品视频一二三四区| 九九热在线免费播放视频| 少妇愉情理伦片丰满丰满午夜| 亚洲精品揄拍自拍首页一| 欧美交a欧美精品喷水| 欧美不卡无线在线一二三区观| 国产精品熟妇视频国产偷人| 亚洲AV无码久久精品成人| 日韩无专区精品中文字幕| 久久久久无码中| 99精品国产综合久久久久五月天| 亚洲乱码一卡二卡卡3卡4卡| 日韩福利片午夜免费观着| 麻豆精产国品一二三产| 国产玖玖视频| 国产精品午夜精品福利| 亚洲一区二区三区影院| 成人精品一区二区三区四| 91久久久久无码精品露脸| 韩国无码AV片午夜福利| 91国内精品久久精品一本| 亚洲国产中文字幕在线视频综合| 98精品全国免费观看视频| 国产永久免费高清在线观看| 久久人爽人人爽人人片av| 中文字幕久区久久中文字幕| 久久97人人超人人超碰超国产| 国产成熟女人性满足视频| 亚洲国产精品久久久天堂麻豆宅男 |