NHibernate:在同一个会话中保存不同类型的对象会中断批处理

时间:2011-02-15 22:54:06

标签: nhibernate fluent-nhibernate

新手在这里,对不起,如果这是一个显而易见的问题。

似乎在同一会话中保存不同类型的对象会中断批处理,导致性能显着下降。

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!

2 个答案:

答案 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类型转到指定的数量,但只有组同类型。虽然交替导致单独的插入语句。