级联多级删除和N + 1

时间:2014-08-05 10:44:47

标签: nhibernate fluent-nhibernate cascade fluent fluent-nhibernate-mapping

我发现级联删除正在发送带有许多个别删除的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

1 个答案:

答案 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