新手在这里,对不起,如果这是一个显而易见的问题。
似乎在同一会话中保存不同类型的对象会中断批处理,导致性能显着下降。
ID生成器设置为Increment(正如Diego Mijelshon建议的那样,我尝试过hilo(“100”),但不幸的是同样的问题,Test1()仍然比Test2()慢大约5倍):
public class CustomIdConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.GeneratedBy.Increment();
}
}
AdoNetBatchSize设置为1000:
MsSqlConfiguration.MsSql2008
.ConnectionString(connectionString)
.AdoNetBatchSize(1000)
.Cache(x => x
.UseQueryCache()
.ProviderClass<HashtableCacheProvider>())
.ShowSql();
这些是模型:
public class TestClass1
{
public virtual int Id { get; private set; }
}
public class TestClass2
{
public virtual int Id { get; private set; }
}
这些是测试方法。 Test1()需要62秒,Test2()只需要11秒。(正如Phill建议的那样,我尝试过无状态会话,但不幸的是同样的问题):
[TestMethod]
public void Test1()
{
int count = 50 * 1000;
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
var x = new TestClass1();
var y = new TestClass2();
session.Save(x);
session.Save(y);
}
transaction.Commit();
}
}
}
[TestMethod]
public void Test2()
{
int count = 50 * 1000;
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
var x = new TestClass1();
session.Save(x);
}
transaction.Commit();
}
}
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
var y = new TestClass2();
session.Save(y);
}
transaction.Commit();
}
}
}
有什么想法吗?
谢谢!
更新
可以从here下载测试项目。您需要在Main方法中更改connectionString。我将所有会话都更改为无状态会话。
我的恢复:Test1 = 59.11,Test2 = 7.60,Test3 = 7.72。 Test1比Test2&amp;慢7.7倍。 TEST3!
答案 0 :(得分:0)
不要使用增量。这是最糟糕的发电机。
尝试将其更改为HiLo。
<强>更新强>
当交替保存不同的实体时,无论会话/事务是否分开,看起来都会出现问题。
这产生与第二种测试方法类似的结果:
[TestMethod]
public void Test3()
{
int count = 50 * 1000;
using (var session = SessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
var x = new TestClass1();
session.Save(x);
}
for (int i = 0; i < count; i++)
{
var y = new TestClass2();
session.Save(y);
}
transaction.Commit();
}
}
}
我的猜测,不考虑NH的来源,是因为实体之间可能存在关系而保留了订单,即使没有。
答案 1 :(得分:0)
当你运行test2和test3时,插件将被一起批处理。
当您运行test1时,替换插入的位置,插入将作为单独的语句发出,而不是一起批处理。
我通过剖析所有三项测试找到了这一点。
根据Diego的回答,它必须保留您插入的顺序,并将它们一起批处理。
我写了第4个测试,我将批量大小设置为10,然后当我从TestClass1更改为TestClass2时交替进行,这样我就可以执行5个TestClass1,然后是5个TestClass2,以达到批量大小。
按照处理顺序推出批次5。
public void Test4()
{
int count = 10;
using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
if (i%2 == 0)
{
for (int j = 0; j < 5; j++)
{
var x = new TestClass1();
session.Save(x);
}
}
else
{
for (int j = 0; j < 5; j++)
{
var y = new TestClass2();
session.Save(y);
}
}
}
transaction.Commit();
}
}
然后我将其更改为一次插入3而不是5.批次是3的倍数,所以必须发生的是批量大小允许批次1类型转到指定的数量,但只有组同类型。虽然交替导致单独的插入语句。