為什么Entity Framework的初始化速度慢如蝸牛呢?
對於在應用程序中定義的每個DbContext類型,在首次使用時,Entity Framework都會根據數據庫中的信息在內存生成一個映射視圖(mapping views),而這個操作非常耗時。
在第1次調用DbContext進行數據庫操作時會進行緩慢的mapping views生成操作,后續的DbContext操作會共享已經生成的mapping views,不受這個問題影響。但是要注意的是你定義的每一個DbContext都會面臨這個問題。
而我們的緩解之道則是在應用程序初始化時一次性觸發所有的DbContext進行mapping views的生成操作——調用StorageMappingItemCollection的GenerateViews()方法。
一、預生成映射視圖
將代碼放在Application_Start中調用PreApplicationStartMethod中執行
private void PreApplicationStartMethod() { using (var dbcontext = new XXXDBContext()) { var objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext; var mappingCollection = (StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace); mappingCollection.GenerateViews(new List<EdmSchemaError>()); } //對程序中定義的所有DbContext逐一進行這個操作 }
在程序更新時只需發一個請求讓程序啟動起來,比如訪問首頁,就可以直接發布。而第1位用戶,等待時間由原來7秒減少到0.5-0.6秒。
二、禁用第一次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加代碼
protected void Application_Start() { //....... RouteConfig.RegisterRoutes(RouteTable.Routes); #if DEBUG BundleTable.EnableOptimizations = false;//關閉文件壓縮功能 #else BundleTable.EnableOptimizations = true;//開啟文件壓縮功能 Database.SetInitializer<MMISDBContext>(null); #endif BundleConfig.RegisterBundles(BundleTable.Bundles); PreApplicationStartMethod(); }
MMISDBContext這是我項目的EF上下方類,你要根據你的項目替換成自己的EF上下方類。
三、安裝Application Initialization
這是在iis8出來后才有的,iis8內置的功能,一些是iis10的配置圖
而對於iis7.5也提供了一個擴展以支持這個功能。
Application Initialization Module for IIS 7.5
在頁面接近底部的地方,找到適合自己架構的安裝鏈接
- x86 for Windows 7
- x64 for Windows 7 or Windows Server 2008 R2
安裝這個iis模塊后,在iis界面中並沒有模塊圖標和配置界面,還需要安裝:
http://pan.baidu.com/s/1c091WxM
安裝成功之后會多了一個配置如下圖:
如果僅配置程序池StartMode為AlwaysRunning還不放心的話, 也可以同時針對站點開啟preload和DoAppInitAfterRestart。
設置應用程序池如下圖:
設置網站如下圖
配置好后,測試了下,效果十分不錯。 回收程序池后首次打開各站點,延遲都很低。 其實這個模塊的思路和定時從外部觸發一個訪問是一樣的,只是,更好的地方在於,它本身在程序池回收重啟的時候就完成了這件事,而不會讓外部訪問有機會遇到首次訪問的情況。
四、用Ngen安裝生成EF的本地鏡像
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的本地鏡像。
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\ngen display EntityFramework
文檔:https://docs.microsoft.com/zh-cn/dotnet/framework/tools/ngen-exe-native-image-generator
五、IIS閑置超時導致變冷
如果你覺得這還沒有解決”過了一段時間不訪問頁面然后再次打開頁面變慢“的問題,而且不能忍受第一次訪問還是有點慢,可以設置應用程序池的”閑時超時“和回收”固定時間間隔“長一些或者建一個計划任務定時去訪問使用了ef的頁面,這樣給ef熱身,讓ef不變冷,這樣可以防止長時間不請求網站,應用程序進程停止再次訪問變慢的問題。設置應用程序池的時間如下圖:
閑時超時默認是20分鍾,如果在超過20分鍾都沒有請求這個應用程序池工作進程就要關閉。這里你可以設置根據自己需要設置長一些。
六、Model和DAl單獨的分層的
原文:
https://blog.csdn.net/qq61714079/article/details/50540318
https://msdn.microsoft.com/en-us/data/dn469601#code
https://msdn.microsoft.com/zh-cn/library/dn292691(v=vs.113).aspx
https://www.cnblogs.com/sunShineJing/p/5083184.html