随着会话的持续,查询和提交需要更长的时间
Queries and Commits take longer as the session lives on
我使用 Fluent NHibernate 将数据导入 SQL 服务器数据库。
我在我的实体上使用了自动映射(效果很好)
Fluently.Configure(nhibernateConfig_)
.Mappings(map_ => map_.AutoMappings.Add(AutoMap
.AssemblyOf<EntityMapping>(new AutomapConfiguration())
.UseOverridesFromAssemblyOf<EntityMapping>()
.Conventions.AddFromAssemblyOf<EntityMapping>()));
并使用 QueryOver 从数据库中获取数据
public AttributeTranslation GetOrCreateAttributeTranslation(Attribute attribute_, string language_)
{
AttributeTranslation translation = _session
.QueryOver<AttributeTranslation>()
.And(trans_ => trans_.Attribute == attribute_)
.And(trans_ => trans_.Language == language_)
.SingleOrDefault();
if (translation == null) {
translation = new AttributeTranslation() {
Language = language_,
Attribute = attribute_
};
Save(translation);
}
return translation;
}
不幸的是,当我处理我的输入时,随着会话的进行,每个要读取的查询和每个已提交的事务花费的时间越来越长。
// Surrounded in several for loops that process the input
using (ITransaction transaction = _repo.BeginTransaction()) {
Stopwatch transGetWatch = Stopwatch.StartNew();
AttributeTranslation translation = _repo.GetOrCreateAttributeTranslation(attribute, lang.Key);
transGetWatch.Stop();
translation.DisplayName = value;
_repo.Save(translation);
Stopwatch commitWatch = Stopwatch.StartNew();
transaction.Commit();
commitWatch.Stop();
Console.Write("\rGetTrans[{0}] Commit[{1}] ",
transGetWatch.ElapsedMilliseconds,
commitWatch.ElapsedMilliseconds);
}
我尝试切换到 HiLo 来生成 ID,但无济于事。
public class AttributeTranslationMapOverride : IAutoMappingOverride<AttributeTranslation>
{
public void Override(AutoMapping<AttributeTranslation> map_)
{
map_.Id(attr_ => attr_.Id).GeneratedBy.HiLo("attributeTranslationMaxLo");
}
}
查询和提交开始时每次调用大约 3-4 毫秒,结束时大约 80 到 100 毫秒。
我不一定需要降低整体性能,我只是希望它稳定在每次调用的初始 3 到 4 毫秒。
这里可能发生了什么?
作为ORM,NHibernate不适合批处理,所以遇到的麻烦。但无论如何它都有一些功能可以帮助将其用于批处理工作。
与 suspected by David Osborne 一样,当使用 ISession
进行批量工作(例如数据导入)时,session 一级缓存可能会变得太大。
您可以选择多种解决方案:
- 按照 David Osborne 的建议和 reference documentation 的建议清除 session (
ISession.Clear
)。如果每一行数据从不引用与前几行相同的某些数据,则在每一行之后进行清除不会有什么坏处。每 50 或 100 行执行一次应该足以避免增加 session 一级缓存对性能造成太大影响。根据您的发现进行调整。
- 会议很便宜。您可以丢弃它并使用新的,而不是清除它。 (但避免在每一行都这样做,它不是完全免费的。)
- 考虑使用 stateless session (
ISessionFactory.OpenStatelessSession()
)。它们可以更适合一些批处理。
备注:
您当前的实施似乎每笔交易只保存一个实体。如果您可以保存一堆相同 类 的实体,您可能会受益于 batching(至少 SQL-Server)并提高性能。它还会减少连接数 releases/re-acquiring,因为默认情况下 SQL 连接会在每次交易后释放。
我使用 Fluent NHibernate 将数据导入 SQL 服务器数据库。
我在我的实体上使用了自动映射(效果很好)
Fluently.Configure(nhibernateConfig_)
.Mappings(map_ => map_.AutoMappings.Add(AutoMap
.AssemblyOf<EntityMapping>(new AutomapConfiguration())
.UseOverridesFromAssemblyOf<EntityMapping>()
.Conventions.AddFromAssemblyOf<EntityMapping>()));
并使用 QueryOver 从数据库中获取数据
public AttributeTranslation GetOrCreateAttributeTranslation(Attribute attribute_, string language_)
{
AttributeTranslation translation = _session
.QueryOver<AttributeTranslation>()
.And(trans_ => trans_.Attribute == attribute_)
.And(trans_ => trans_.Language == language_)
.SingleOrDefault();
if (translation == null) {
translation = new AttributeTranslation() {
Language = language_,
Attribute = attribute_
};
Save(translation);
}
return translation;
}
不幸的是,当我处理我的输入时,随着会话的进行,每个要读取的查询和每个已提交的事务花费的时间越来越长。
// Surrounded in several for loops that process the input
using (ITransaction transaction = _repo.BeginTransaction()) {
Stopwatch transGetWatch = Stopwatch.StartNew();
AttributeTranslation translation = _repo.GetOrCreateAttributeTranslation(attribute, lang.Key);
transGetWatch.Stop();
translation.DisplayName = value;
_repo.Save(translation);
Stopwatch commitWatch = Stopwatch.StartNew();
transaction.Commit();
commitWatch.Stop();
Console.Write("\rGetTrans[{0}] Commit[{1}] ",
transGetWatch.ElapsedMilliseconds,
commitWatch.ElapsedMilliseconds);
}
我尝试切换到 HiLo 来生成 ID,但无济于事。
public class AttributeTranslationMapOverride : IAutoMappingOverride<AttributeTranslation>
{
public void Override(AutoMapping<AttributeTranslation> map_)
{
map_.Id(attr_ => attr_.Id).GeneratedBy.HiLo("attributeTranslationMaxLo");
}
}
查询和提交开始时每次调用大约 3-4 毫秒,结束时大约 80 到 100 毫秒。
我不一定需要降低整体性能,我只是希望它稳定在每次调用的初始 3 到 4 毫秒。
这里可能发生了什么?
作为ORM,NHibernate不适合批处理,所以遇到的麻烦。但无论如何它都有一些功能可以帮助将其用于批处理工作。
与 suspected by David Osborne 一样,当使用 ISession
进行批量工作(例如数据导入)时,session 一级缓存可能会变得太大。
您可以选择多种解决方案:
- 按照 David Osborne 的建议和 reference documentation 的建议清除 session (
ISession.Clear
)。如果每一行数据从不引用与前几行相同的某些数据,则在每一行之后进行清除不会有什么坏处。每 50 或 100 行执行一次应该足以避免增加 session 一级缓存对性能造成太大影响。根据您的发现进行调整。 - 会议很便宜。您可以丢弃它并使用新的,而不是清除它。 (但避免在每一行都这样做,它不是完全免费的。)
- 考虑使用 stateless session (
ISessionFactory.OpenStatelessSession()
)。它们可以更适合一些批处理。
备注:
您当前的实施似乎每笔交易只保存一个实体。如果您可以保存一堆相同 类 的实体,您可能会受益于 batching(至少 SQL-Server)并提高性能。它还会减少连接数 releases/re-acquiring,因为默认情况下 SQL 连接会在每次交易后释放。