转自:http://www.lanhusoft.com/Article/127.html
最近项目在使用EF了,mvc使用EF确实方便,因为添加功能的时候可以使用vs自动生成用ef的增、删、查、改的模板,大的提高的工作效率。但是很多人都遇到过用EF开发的程序在第一次访问的时候会比用ADO纯sql慢很多,过一段时间不访问又会变慢。我最近的两个项目分别是蓝狐软件工作室和一个商城系统都是用MVC5+EF6 Code First开发的,都遇到过这样的问题。下面我就分享一下我们蓝狐在这个优化的过程中使用的解决办法。
我使用MiniProfiler.EF来监控来诊断到底是什么导致页面第一次访问为什么这么慢。监控到的结果如下图:
再次访问结果:
隔很久不访问再次访问页面响应时间也能保持4-8秒内。
MVC的程序第一次访问比较慢的的问题由于第一次是要处理视图文件.cshtml(生成为.cs文件)、加载引用的dll程序文件和初始化程序池等等。
这是在iis8出来后才有的,iis8内置的功能,而对于iis7.5也提供了一个扩展以支持这个功能。
Application Initialization Module for IIS 7.5
在页面接近底部的地方,找到适合自己架构的安装链接
安装这个iis模块后,在iis界面中并没有模块图标和配置界面,还需要安装:
http://pan.baidu.com/s/1c091WxM
安装成功之后会多了一个配置如下图:
如果仅配置程序池StartMode为AlwaysRunning还不放心的话,
也可以同时针对站点开启preload和DoAppInitAfterRestart。
设置应用程序池如下图:
设置网站如下图
配置好后,测试了下,效果十分不错。
回收程序池后首次打开各站点,延迟都很低。
其实这个模块的思路和定时从外部触发一个访问是一样的,只是,更好的地方在于,它本身在程序池回收重启的时候就完成了这件事,而不会让外部访问有机会遇到首次访问的情况。
使用了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
Application_Start加代码
Database.SetInitializer<lanhuBlog.DAL.BlogContext>(null);
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逐一进行这个操作 }
如果你觉得这还没有解决”过了一段时间不访问页面然后再次打开页面变慢“的问题,而且不能忍受第一次访问还是有点慢,可以设置应用程序池的”闲时超时“和回收”固定时间间隔“长一些或者建一个计划任务定时去访问使用了ef的页面,这样给ef热身,让ef不变冷,这样可以防止长时间不请求网站,应用程序进程停止再次访问变慢的问题。设置应用程序池的时间如下图:
闲时超时默认是20分钟,如果在超过20分钟都没有请求这个应用程序池工作进程就要关闭。这里你可以设置根据自己需要设置长一些。