【发布时间】:2011-10-03 17:56:39
【问题描述】:
我有 3 个通过 NHibernate 映射的类:交叉路口、车辆和区域。
我的交叉点类包含属于交叉点的区域列表。我的 Vehicle 类包含 Vehicle 包含的区域列表。最后,我的 Zone 类包含一个包含 Zone 的 Vehicles 列表。
我的测试性能集包含 10,000 辆汽车、500 个区域和 250 个交叉路口。对于所有这些对象,我的 Zones 和 Vehicles 都映射了列表的加载时间大约是 27 分钟。
我不确定发生了什么,但这两个列表至少没有优化。如果我将 Vehicle 列表从 Zone 类映射中取出,则保存对象会有 10 分钟的差异。这似乎有点偏离了这两个列表是如何直接相关的。
似乎 NHibernate 正在递归地保存两个列表中的项目,并为保存过程增加了一堆开销。有什么方法可以优化这些列表以更快地保存对象?
这是我的 Intersection 和 Vehicle 都继承自的 Device 映射:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Devices.Device, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Device`">
<id name="PK" type="System.Int64, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="PK" />
<generator class="identity" />
</id>
<version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" />
<joined-subclass name="EMTRAC.Intersections.Intersection, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<key>
<column name="Device_id" />
</key>
<component name="Zones" access="property">
<bag name="_list" cascade="all-delete-orphan" access="field" fetch="join" inverse="false">
<key>
<column name="Zone_PK" />
</key>
<many-to-many class="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bag>
</component>
<property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</property>
</joined-subclass>
<joined-subclass name="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<key>
<column name="Device_id" />
</key>
<component name="Zones" access="property">
<bag name="_list" cascade="save-update" access="field" table="VehicleZones" inverse="true">
<key>
<column name="veh_id" not-null="true"/>
</key>
<many-to-many class="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bag>
</component>
<property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</property>
</joined-subclass>
</class>
</hibernate-mapping>
最后是我对 Zone 类的映射:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Zone`">
<id name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="PK"/>
<generator class="identity" />
</id>
<version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" />
<property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</property>
<component name="Vehicles" access="property">
<bag name="_list" cascade="save-update" access="field" table="VehicleZones">
<key>
<column name="veh_id" not-null="true"/>
</key>
<many-to-many class="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bag>
</component>
</class>
</hibernate-mapping>
任何想法如何提高这些列表的效率?现在它保存它们的每个表都包含 500,000 条记录,当然加载它们并保存这么多记录需要一些时间。
编辑
我删除了所有我忘记删除的lazy="false" 部分,它的速度大大提高了。我还对对象的保存和加载进行了一些调整,将部分分解为单独的线程以提高性能,并在 NHibernate 中实现事务的使用似乎有所帮助。
但是我遇到了一个障碍。我现在无法保存这两个列表。在将列表添加到车辆和区域之前,我已经预先保存了所有交叉路口、车辆和区域。但是,如果我在区域映射中包含车辆列表,我会在尝试更新车辆和列表时遇到错误。代码如下:
using (var tx = session.BeginTransaction())
{
foreach (Vehicle vehicle in Program.data.Vehicles.list)
{
session.Update(vehicle);
}
tx.Commit();
}
我收到堆栈溢出异常。有什么想法吗?
你知道如何解决这个问题吗?
编辑 有没有办法将 Zone 类中的 Vehicles 列表和 Vehicle 类中的 Zones 列表映射到同一个表,这样它就不会递归地遍历这两个列表?这些列表相互关联。一个是车辆所属的区域列表,另一个是区域所属的车辆列表。在深入研究之后,我认为我没有正确映射。
编辑 我一直在使用我相信的正确映射取得进展。我发布了一个更简化版本的 Device 映射,它映射了 Intersection 和 Vehicle 类,以及一个简化版本的 Zone,它当然映射了 Zone 类。
这似乎保存得比较好,但有一个例外。出于某种原因,保存大量项目会抛出 Stack Overflow 异常。这是我正在使用的方法:
// Create a Transaction for batch updating
using (var tx = session.BeginTransaction())
{
foreach (Vehicle veh in Program.data.Vehicles.list)
{
session.Save(veh);
}
// Commit transactions
tx.Commit();
}
这适用于 250 个十字路口、500 个区域和 1000 辆车。但是,我试图创建一个测试数据集以在更极端的环境中强调这一点,并且在尝试将测试数据保存到数据库通过这种方式。
有什么想法吗?
【问题讨论】:
标签: nhibernate nhibernate-mapping