我发现级联删除正在发送带有许多个别删除的SQL,即N + 1问题。
我有三个表:User,UserAttribute和Attribute。每个用户都有许多UserAttributes,每个UserAttribute都有一个属性 - 由以下地图表示:
public UserMap() {
Id(x => x.Id);
Map(x => x.Description);
HasMany(x => x.Attributes)
.Inverse()
.Cascade.AllDeleteOrphan();
}
public UserAttributeMap() {
Id(x => x.Id);
References(x => x.User)
.Not.Nullable();
References(x => x.Attribute)
.Not.Nullable()
.Cascade.All();
}
public AttributeMap() {
Id(x => x.Id);
Map(x => x.Name)
.Unique();
}
在上面的测试场景中,我的架构随后使用FluentNH生成。
我遇到的问题是,当我删除用户实体时,级联为每个UserAttribute和每个属性生成一个单独的删除;这是一个潜在的大型性能问题(用户通常可能有数百个Atributes)。
映射会出现明显错误,会触发N + 1问题吗?有什么办法可以阻止吗?这是疯狂的谈话吗?
作为旁注,我的NHibernate配置已包含大批量,但据我所知,批处理不会包含这样的内容?当我描述它们时,它们肯定不会被批量化。
NHibernate v3.3.1.4000
FluentNHibernate v 1.4.0.0
UserTable:
Id
Description
UserAttributeTable:
Id
User_id (FK)
Attribute_id (FK)
AttributeTable:
Id
Name
答案 0 :(得分:0)
您正在体验的删除过程,按步骤逐个执行是设计使然。原因是:
删除操作比任何读取操作都少见。因此,删除时不支持为读取实现的批处理。
查看强大的批量支持以进行读取操作:
如果我们真的想提高删除过程的性能,我们可以使用:
......如前所述,自动和透明的对象/关系映射与对象状态的管理有关。这意味着对象状态在内存中可用,因此直接在数据库中操作(使用SQL数据操作语言( DML )语句:
INSERT, UPDATE, DELETE
)数据不会影响内存状态。但是,NHibernate提供了通过Hibernate查询语言(HQL)执行批量SQL样式DML语句执行的方法......
该资源的代码示例:
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
String hqlDelete = "delete Customer c where c.name = :oldName";
// or String hqlDelete = "delete Customer where name = :oldName";
int deletedEntities = s.CreateQuery( hqlDelete )
.SetString( "oldName", oldName )
.ExecuteUpdate();
tx.Commit();
session.Close();
我们可以看到,在DB端执行的SQL语句没有将任何实体加载到应用层。这意味着,我们根本没有从级联中获利,但我们可以提高性能。
总结:NHibernate支持对Read操作进行批处理。级联是逐个触发的。我们可以跳过级联并使用HQL在我们的实体上优化DELETE