建立mvc web application,採用code first 的方式,MVC5,EF6.0 整了一個網站。開發完以後。直接publish。就這樣部署到服務器上了。web
在使用過程當中發現,網站打開的速度有點慢。並且每隔一段時間不使用,網站的打開速度就變慢。sql
問題分析:數據庫
一開始首先想到的是IIS的應用程序池釋放的問題。瀏覽器
後來配置了iis仍是過一段時間訪問變慢。bash
後來爲了快速解決這個問題,只能先作了一個bat文件,在服務器端模擬一段時間內訪問這個網站一下。這樣用戶在訪問的時候不會體會到網站的訪問速度變慢的問題。服務器
@echo 正在關掉全部的IE進程(須要設置默認瀏覽器是IE)
taskkill /im iexplore.exe /f /t
@echo 正在經過ping來延遲80秒鐘,以方便IE打開頁面
ping 127.0.0.1 -n 10
@echo 正在訪問 http://localhost
start "C:\Program Files\Internet Explorer\iexplore.exe" http://localhost
這樣隔一段時間變慢的問題已經解決了,可是尚未查找到這是什麼緣由。架構
後來看到一篇文章說 是由於EF 的緣由。mvc
EF方面的緣由:app
一、Code First第一次啓動會對比程序中的Model與數據庫表(database initializer ),生成Model與數據庫的映射視圖
二、隨着EF的開源,EF從6開始就不會包含在.net Framework中,安裝.net Framework默認是不會安裝EF的。所以EF程序集就沒有生成本地鏡像,這樣每次程序啓動,EF的代碼都會經過just-in-time (JIT) compiler(即時編譯器)把MSIL中間代碼編譯成本機能識別的本地代碼。由於這個生成的本地代碼存在程序運行的進程裏面的內存中,它將回收當程序進程被終止(例如:iis程序池回收,程序池默認是按需觸發運行的,沒人訪問它就不啓動了)。因爲EF框架仍是比較大的,EF6文件大小到4-5M了,因此每次啓動都要重寫編譯本地代碼有比較明顯的性能影響。
第2、優化方案框架
我主要是經過如下幾方面來優化
1、安裝Application Initialization
若是僅配置程序池StartMode爲AlwaysRunning還不放心的話, 也能夠同時針對站點開啓preload和DoAppInitAfterRestart。
設置應用程序池以下圖:
設置網站以下圖
配置好後,測試了下,效果十分不錯。 回收程序池後首次打開各站點,延遲都很低。 其實這個模塊的思路和定時從外部觸發一個訪問是同樣的,只是,更好的地方在於,它自己在程序池回收重啓的時候就完成了這件事,而不會讓外部訪問有機會遇到首次訪問的狀況。
2、用Ngen安裝生成EF的本地鏡像
一、打開cmd窗口
二、定位到dll所在的目錄,如:cd d:\website1\bin,切換到程序的bin目錄。
三、運行ngen命令
For 32 bit run:
%WINDIR%\Microsoft.NET\Framework\v4.0.30319\ngen install EntityFramework.SqlServer.dll
For 64 bit run: %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\ngen install EntityFramework.SqlServer.dll
注意:這裏根據你本身機器(是32仍是64)和.net版本,選擇相應的命令,只須要安裝EntityFramework.SqlServer.dll,由於安依賴EntityFramework.dll,會自動安裝生成EntityFramework.dll的本地鏡像。
3、禁用第一次ef查詢對錶__MigrationHistory的問題
使用了ef的Code first會在第一次ef查詢的時候會對__MigrationHistory訪問,是爲了檢查數據庫和model是否匹配,以保證ef能正常運行。經過監測會先執行下面的sql:
- SELECT
- [GroupBy1].[A1] AS [C1]
- FROM ( SELECT
- COUNT(1) AS [A1]
- FROM [dbo].[__MigrationHistory] AS [Extent1]
- ) AS [GroupBy1]
- GO
- SELECT TOP (1)
- [Extent1].[Id] AS [Id],
- [Extent1].[ModelHash] AS [ModelHash]
- FROM [dbo].[EdmMetadata] AS [Extent1]
- ORDER BY [Extent1].[Id] DESC
- GO
這段sql語句其實中只是在開發的時候有用,發佈到生產環境,能夠把這個給禁用了以提升性能。解決辦法:
Application_Start加代碼
- Database.SetInitializer<lanhuBlog.DAL.BlogContext>(null);
lanhuBlog.DAL.BlogContext這是我項目的EF上下方類,你要根據你的項目替換成本身的EF上下方類。
4、Model和DAl單獨的分層的
用vs建一個mvc項目,Model、DAL、Controller、View都在Web項目裏面。爲了減小model和DAL致使從新編譯dll帶來的性能影響。我把Model和DAL都單獨的分層,編譯成單獨的dll了。
5、EF Pre-Generated Mapping Views(預生成映射視圖)
Application_Start加入下面代碼:
- using (var dbcontext = new EFDbContext())
- {
- var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;
- var mappingCollection = (StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
- mappingCollection.GenerateViews(new List<EdmSchemaError>());
- //對程序中定義的全部DbContext逐一進行這個操做
- }
6、補充
若是你以爲這尚未解決」過了一段時間不訪問頁面而後再次打開頁面變慢「的問題,並且不能忍受第一次訪問仍是有點慢,能夠設置應用程序池的」閒時超時「和回收」固定時間間隔「長一些或者建一個計劃任務定時去訪問使用了ef的頁面,這樣給ef熱身,讓ef不變冷,這樣能夠防止長時間不請求網站,應用程序進程中止再次訪問變慢的問題。設置應用程序池的時間以下圖:
閒時超時默認是20分鐘,若是在超過20分鐘都沒有請求這個應用程序池工做進程就要關閉。這裏你能夠設置根據本身須要設置長一些。