在程序启动时,我正在将整个数据库的完整对象图加载到域对象中,而不是延迟加载。我知道这不是典型的用法,但这不在问题之内。该数据库仅由单个用户/程序访问。以下条件是关于这个单启动加载操作;
随着数据库的增长,加载时间变得越来越长。我有这些数字用于同一数据库的两个状态;
1. Size 1.6MB, 3 main tables row count; 1100, 2400, 13400. Load time; 44s
2. Size 3.6MB, 3 main tables row count; 2800, 6200, 26700. Load time; 3m 40s
这3个表有这些列;
7x integer, 4x numeric, 6x text, 2x datetime (2800 rows)
7x integer, 3x numeric, 11x text, 2x datetime (6200 rows)
4x integer, 2x numeric, 5x text, 1x datetime (26700 rows)
所有映射均为1:m
。
CPU Profiler显示了这一点; http://img585.imageshack.us/img585/4444/6rh.png
欣赏建议;
编辑:
映射;
public class AccountBaseMap : ClassMap<AccountBase>
{
public AccountBaseMap()
: base()
{
Id(x => x.Id).GeneratedBy.Identity();
HasMany(x => x.Executions).KeyColumn("Account__Id").Cascade.All();
HasMany(x => x.Orders).KeyColumn("Account__Id").Cascade.All();
//...value types omitted
References(x => x.RiskProfile).Cascade.All();
}
}
public class LocalOrderMap : ClassMap<LocalOrder>
{
public LocalOrderMap()
: base()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Account__Id);
//...value types omitted
HasMany(x => x.StatusDetails).KeyColumn("Order__id").Cascade.All();
}
}
public class OrderStatusDetailMap : ClassMap<OrderStatusDetail>
{
public OrderStatusDetailMap()
: base()
{
Id(x => x.Id).GeneratedBy.Identity();
//...value types omitted
Map(x => x.Order__Id);
Map(x => x.Time).CustomType("timestamp");
}
}
NHibernate ShowSql,来自查询;
_session.CreateCriteria(T)()列表(T)();
输出; (约有1000行,类似于......删除)
http://textuploader.com/?p=6&id=ie7mn
编辑2:
NHibernate配置;
var fcfg = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.ConnectionString(connString));
fcfg.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TMap1>().Conventions.Add(FluentNHibernate.Conventions.Helpers.DefaultLazy.Never()));
if (typeof(TMap1) != typeof(TMap2))
fcfg.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TMap2>().Conventions.Add(FluentNHibernate.Conventions.Helpers.DefaultLazy.Never()));
fcfg.ExposeConfiguration(c => cfg = c).Cache(c => c.UseQueryCache());
sessionFactory = fcfg.BuildSessionFactory();
我不使用任何日志记录框架,因此请不要记录日志。虽然我目前运行的是Debug版本,但应检查Release版本是否有所不同。
关于建筑;解决方案设置为Any CPU,项目构建到x86(平台目标)。我在x86 XP和x64 Windows 7上运行,并基于此加载正确的System.Data.SQLite.dll。
是的,我正在使用NHibernate 3.1.0.4
答案 0 :(得分:0)
如果一切都失败了:
在NHibernate中记录所有内容(尤其是3.x或更高版本)可能会在调试时导致重大性能问题。
答案 1 :(得分:0)
因为你在另一侧有反向引用设置反向
// in Accountmap
HasMany(x => x.Executions).KeyColumn("Account__Id").Cascade.All().Inverse();
HasMany(x => x.Orders).KeyColumn("Account__Id").Cascade.All().Inverse();
// in Accountmap
HasMany(x => x.StatusDetails).KeyColumn("Order__id").Cascade.All().Inverse();
反向引用应该是引用而不是属性
Map(x => x.Account__Id); -> References(x => x.Account);
Map(x => x.Order__Id); -> References(x => x.Order);
在查询时使用期货批量查询以便在一次往返中获取数据
// ignore the results, the query only loads the data into session cache
session.QueryOver<Order>()
.Fetch(x => x.StatusDetails).Eager
.Future();
var accounts = session.QueryOver<AccountBase>()
.Fetch(x => x.Orders).Eager
.Future();
return accounts.ToList(); // both queries execute here
检查你的equals和gethashcode实现,以便将id考虑在内以防止核心器例中的错误
public override bool Equals(object obj)
{
var other = obj as AccountBase;
return other != null && IsTransient ? ReferenceEquals(this, other) : Id == other.Id;
}
private bool IsTransient { get { return Id == 0; } }
private int? _cachedHashcode;
public override int GetHashcode()
{
if (!_cachedHashcode.HasValue)
_cachedHashcode = IsTransient ? base.GetHashCode() : Id.GetHashCode();
return _cachedHashcode.Value;
}
还有一些小调整:
将Defaultlazy.Never()延迟到实际用例
var fcfg = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.ConnectionString(connString))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TMap1>())
.Cache(c => c.UseQueryCache());
if (typeof(TMap1) != typeof(TMap2))
fcfg.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TMap2>()));
cfg = fcfg.BuildConfiguration();
sessionFactory = cfg.BuildSessionFactory();
答案 2 :(得分:0)
终于发现我只需改变一件事;
在我的班级地图中,添加到所有1:M集合Fetch.Subselect()
HasMany(x =&gt; x.Orders)。 Fetch.Subselect() .KeyColumn(&#34; Account _Id&#34;)。Not.LazyLoad()。Cascade.All() .Inverse();
(我还在那里添加了Not.LazyLoad()
,但没有区别,因此可以省略)
通过此更改,我可以保持流畅的配置约定DefaultLazy.Never
,这很好,因为我不需要将属性和方法设置为虚拟。我可以保持单向关系。基本上,除了这个细节之外,我之前的代码没有任何变化或特殊调整。
当前数据库的加载时间,现在4.8mb从11分钟下降到13秒。