使用Entity Framework 4.1版本的Code-First,性能非常慢
本文关键字:Code-First 性能 非常 版本 Entity Framework 使用 | 更新日期: 2023-09-27 18:04:56
我们公司正在开发一个新的应用程序,它的核心是一个比较大的业务数据对象。我们决定先用代码尝试实体框架,将数据库从应用程序中抽象出来,但结果出了问题。业务对象由大约60个类和总共大约600个属性组成;然而,它是一个树结构,没有交叉/回溯指针。
我们的测试是向数据库中添加一个未初始化的类实例。使用DbContext。在我的开发机器上添加我们的数据结构花了8分钟。这是这种大小的对象的预期性能吗?是否有导致实体框架性能不佳的常见问题列表?我觉得这件事我需要帮助。
更多的数据点:在业务对象的根下的第一级有27个元素。如果有3个元素(其余的注释掉了),添加的时间是4.5秒。如果有5个元素,则需要11.8秒。有8种元素,1分12.5秒。显然,这些元素的大小变化很大,但这些似乎确实表明了某种系统问题。
…我们的测试是添加一个类的未初始化实例到数据库。使用DbContext.Add…
在调用Add
之前,您是否确保创建了代码优先模型并将其加载到内存中?我的意思是:如果您使用像这样的测试代码…
using (var context = new MyContext())
{
var myHugeBusinessObject = CreateItSomeHow();
context.HugeBusinessObjects.Add(myHugeBusinessObject);
context.SaveChanges();
}
…这是您第一次在测试应用程序中使用上下文,Add
在开始将对象添加到上下文之前,实际上会花一些时间在内存中构建EF模型。
你可以简单地通过在调用Add
之前添加一个虚拟方法来分离这两个步骤,例如:
context.HugeBusinessObjects.Count();
我已经建立了一个测试:
public class MyClass
{
public int Id { get; set; }
public string P1 { get; set; }
// ... P2 to P49
public string P50 { get; set; }
public MyClass Child1 { get; set; }
// ... Child1 to Child26
public MyClass Child27 { get; set; }
}
我创建了一个对象:
var my = new MyClass();
MyClass child = my;
for (int i = 0; i < 100; i++)
{
child.Child1 = new MyClass();
child = child.Child1;
}
child = my;
for (int i = 0; i < 100; i++)
{
child.Child2 = new MyClass();
child = child.Child2;
}
// and so on up to Child27
这个对象图有2700个子对象,每个子对象有50个标量属性。然后我测试了这段代码:
using (var context = new MyContext())
{
var my = CreateWithTheCodeAbove();
context.MyClassSet.Count();
context.MyClassSet.Add(my);
context.SaveChanges();
}
...Count()
(=建立EF模型)大约需要25秒。Add
需要1秒。(在上面的循环中,将100更改为1000(图表中有27000个对象)将Add
的时间几乎线性地增加到9-10秒。)此结果与将AutoDetectChangesEnabled
设置为true
或false
无关。
Child28
到Child47
)添加到MyClass
,那么构建模型(示例代码中的Count()
)所花费的时间将爆炸到140秒。Add
的持续时间只随附加属性线性增加。
所以,我的假设是:您实际上并没有测量将业务对象添加到上下文中的时间,而是度量EF在内存中构建EF模型所需的时间。构建模型的时间似乎随着模型的复杂性呈指数级增长:类上的导航属性数量,可能还包括不同涉及类的数量。
要分离这些步骤,请使用上面建议的一些虚拟调用进行测试。如果你已经分开了…天哪,忘了这篇文章吧。
所以,找到了问题所在。在继续使用NHibernate的过程中,我们遇到了一个结构性错误,这是一些实验性代码。类别正在订阅其子类的PropertyChanged事件,这导致NHibernate崩溃。
这很好!这告诉我们确实有问题。实体框架只是永远运行,没有任何迹象表明这是一个问题,我们可以做些什么。
无论如何,我们暂时会继续使用NHibernate。我们喜欢使用它来控制数据库结构