mvc-mini-profiler 减慢实体框架
Posted
技术标签:
【中文标题】mvc-mini-profiler 减慢实体框架【英文标题】:mvc-mini-profiler slows down Entity Framework 【发布时间】:2011-06-23 12:29:35 【问题描述】:我已经针对我的 Entity Framework 驱动的 MVC 3 站点设置了 mvc-mini-profiler。一切都已适当配置;在 Application_Start 中开始分析,在 Application_End 中结束,依此类推。分析部分工作得很好。
但是,当我尝试将我的数据模型对象生成交换为提供可分析的版本时,性能会变慢。不是每个 SQL 查询,但有些查询大约需要整个页面加载的 5 倍。 (启动 IIS Express 后的第一个页面加载需要更长的时间,但这是持续的。)
查询、执行和“读取数据”SQL 所花费的时间可以忽略不计(大约 2 毫秒),而这一行:
var person = dataContext.People.FirstOrDefault(p => p.PersonID == id);
...当包裹在 using(profiler.Step())
中时,记录为花费 300-400 毫秒。我使用 dotTrace 进行了分析,这证实了实际上在 EF 中花费的时间与往常一样(可分析的组件确实出现非常短暂),只是花费的时间更长。
这让我相信连接或其某些组成部分缺少足够的数据,从而使 EF 的性能更差。
这是我用来制作上下文对象的东西(我的 edmx 模型的类称为 DataContext):
var conn = ProfiledDbConnection.Get(
/* returns an SqlConnection */CreateConnection());
return CreateObjectContext<DataContext>(conn);
我最初使用的是 mvc-mini-profiler 提供的ObjectContextUtils.CreateObjectContext
方法。我深入研究并注意到它设置了一个通配符元数据工作区路径字符串。由于我将数据库层隔离到一个项目和几个 MVC 站点作为使用代码的其他项目,因此这些路径已经改变,我宁愿更具体。另外,我认为这是性能问题的原因。我将CreateObjectContext
功能复制到我自己的项目中以提供此功能,例如:
public static T CreateObjectContext<T>(DbConnection connection) where T : System.Data.Objects.ObjectContext
var workspace = new System.Data.Metadata.Edm.MetadataWorkspace(
GetMetadataPathsString().Split('|'),
// ^-- returns
// "res://*/Redacted.csdl|res://*/Redacted.ssdl|res://*/Redacted.msl"
new Assembly[] typeof(T).Assembly );
// The remainder of the method is copied straight from the original,
// and I carried over a duplicate CtorCache too to make this work.
var factory = DbProviderServices.GetProviderFactory(connection);
var itemCollection = workspace.GetItemCollection(System.Data.Metadata.Edm.DataSpace.SSpace);
itemCollection.GetType().GetField("_providerFactory", // <==== big fat ugly hack
BindingFlags.NonPublic | BindingFlags.Instance).SetValue(itemCollection, factory);
var ec = new System.Data.EntityClient.EntityConnection(workspace, connection);
return CtorCache<T, System.Data.EntityClient.EntityConnection>.Ctor(ec);
...但它似乎并没有太大的区别。无论我使用上述更具体的元数据工作区路径还是 mvc-mini-profiler 提供的版本,问题仍然存在。我只是想我会提到我也尝试过。
用尽了这一切,我已经束手无策了。再一次:当我像往常一样提供我的数据上下文时,没有性能损失。当我提供“可分析的”数据上下文时,某些查询的性能会下降(我也不知道是什么影响了这一点)。 mvc-mini-profiler 做错了什么?我还在给它输入错误的数据吗?
我认为这与this person 遇到的问题相同。
【问题讨论】:
我是在您提供的链接中遇到同样问题的人。我希望我们能找到解决办法。 我将此转发给 EF 团队...希望我们能得到一些指导 @Jesper 也:如果有人可以为我提供一个简单的重现解决方案,我承诺会调试并弄清楚发生了什么。请参阅:code.google.com/p/mvc-mini-profiler/issues/detail?id=43 和 ***.com/questions/6613180/… 【参考方案1】:我今天刚刚解决了这个问题。
见:http://code.google.com/p/mvc-mini-profiler/issues/detail?id=43
它的发生是因为我们的一些花哨的 hack 缓存不够好。特别是:
var workspace = new System.Data.Metadata.Edm.MetadataWorkspace(
new string[] "res://*/" ,
new Assembly[] typeof(T).Assembly );
是一个非常昂贵的调用,所以我们需要缓存工作区。
【讨论】:
不错。我之前浏览过你的代码,我完全错过了。 确实解决了。谢谢!现在我正在与会话状态锁定争用作斗争,在分析器启动和 MVC 开始工作之间增加了 500 毫秒。乐趣永无止境。 @Jesper 你有复制品吗,这是我们的错吗? @Sam:不,我认为我只是公开触发了 ASP.NET 众所周知的会话状态读写器锁。 It's basically this issue。尽管通过了许多 MVC 项目和一些 Web 窗体项目,但我设法没有触发此问题,但即使没有迷你分析器,它似乎也会发生。【参考方案2】:分析,by definition,将影响正在分析的应用程序的性能。分析器需要在整个应用程序中插入它自己的方法调用,拦截低级系统调用,并将所有数据记录在某个地方(意味着写入磁盘)。所有这些任务都会占用宝贵的 CPU 周期、内存和磁盘访问。
【讨论】:
哦,当然,我理解这一点,并且我对这种权衡感到很自在,但这是在一小部分看似微不足道的操作中的显着增加。性能也不是同样或大致同样地全面下降。一些实现更多对象的查询也更快。这是一个可重复的明显异常值,似乎没有任何原因。 您是否尝试过任何通用分析工具,看看它们是否表现出相同的性能问题? 是的;问题指出我在安装此分析器时使用 dotTrace 来查明热路径。 (到处的执行速度都慢了下来。)问题是这怎么没有意义,我希望我只是没有把它设置好。根据通用定义,mvc-mini-profiler 并不是真正的分析器,因为它不会利用所有内容来检测执行,但它满足了其他难以满足的需求(访问其网站以获得更深入的论文)所以如果我只需要在需要重型火炮时才使用 dotTrace,我会非常高兴。 澄清:我使用 dotTrace 试图找出 EF 或 mvc-mini-profiler 正在做什么来特别减慢一件事。禁用 mvc-mini-profiler 后,无论我是否使用 dotTrace 进行分析,我都看不到这种差异。 Ryan,这是一个明显的错误 - 迷你探查器是一种生产安全探查器,无论是探查还是不探查,影响都非常小。 EF比较奇怪,很难拦截以上是关于mvc-mini-profiler 减慢实体框架的主要内容,如果未能解决你的问题,请参考以下文章
是否可以将 mvc-mini-profiler 与类型化数据集一起使用?