简体   繁体   English

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

[英]NHibernate: Saving different types of objects in the same session breaks batching

newbie here, sorry if this is an obvious question. 这里的新手,很抱歉,如果这是一个明显的问题。

It seems saving different types of objects in the same session breaks batching, cause significant performance drop. 似乎在同一会话中保存不同类型的对象会中断批处理,从而导致性能显着下降。

ID generator is set to Increment (as Diego Mijelshon advised, I tried hilo("100"), but unfortunately same issue, Test1() is still about 5 times slower than Test2()): ID生成器设置为Increment(正如Diego Mijelshon所建议的,我尝试了hilo(“ 100”),但不幸的是,相同的问题,Test1()仍然比Test2()慢5倍):

public class CustomIdConvention : IIdConvention
{
    public void Apply(IIdentityInstance instance)
    {
        instance.GeneratedBy.Increment();
    }
}

AdoNetBatchSize is set to 1000: AdoNetBatchSize设置为1000:

MsSqlConfiguration.MsSql2008
.ConnectionString(connectionString)
.AdoNetBatchSize(1000)
.Cache(x => x
    .UseQueryCache()
    .ProviderClass<HashtableCacheProvider>())
.ShowSql();

These are the models: 这些是模型:

public class TestClass1
{
    public virtual int Id { get; private set; }
}

public class TestClass2
{
    public virtual int Id { get; private set; }
}

These are the test methods. 这些是测试方法。 Test1() takes 62 seconds, Test2() takes only 11 seconds. Test1()需要62秒,Test2()仅需要11秒。 (as Phill advised, I tried stateless sessions, but unfortunately same issue): (正如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();
            }
        }
    }

Any ideas? 有任何想法吗?

Thanks! 谢谢!

Update: 更新:

The test project can be downloaded from here . 可以从此处下载测试项目。 You need to change the connectionString in the Main method. 您需要在Main方法中更改connectionString。 I changed all sessions to stateless sessions. 我将所有会话更改为无状态会话。

My restuls: Test1 = 59.11, Test2 = 7.60, Test3 = 7.72. 我的评论是:Test1 = 59.11,Test2 = 7.60,Test3 = 7.72。 Test1 is 7.7 times slower than Test2 & Test3! Test1比Test2和Test3慢7.7倍!

Do not use increment. 不要使用增量。 It's the worst possible generator. 这是最糟糕的发电机。

Try changing it to HiLo. 尝试将其更改为HiLo。

Update: 更新:

It looks like the problem occurs when alternating saves of different entities, regardless of whether the session/transaction are separated or not. 看起来,当交替保存不同实体时,无论会话/事务是否分离,都会出现问题。

This produces similar results to the second test method: 产生的结果与第二种测试方法类似:

[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();
        }
    }
}

My guess, without looking at NH's sources, is that it preserves the order because of possible relationships between the entities, even when there are none. 我的猜测,不考虑NH的来源,是因为实体之间可能存在的关系,即使没有实体之间的关系,它也保留了顺序。

When you run test2 and test3, the insert's are batched together. 当您运行test2和test3时,插入件将一起批处理。

When you run test1, where you alternate the inserts, the inserts are issued as separate statements and are not batched together. 当您运行test1时,在其中交替插入,插入将作为单独的语句发出,并且不会一起批处理。

I found this out by profiling all three tests. 我通过分析所有三个测试发现了这一点。

So as per Diego's answer, it must preserve the order that you're inserting, and batch them together. 因此,按照迭戈的回答,它必须保留您要插入的顺序,并将它们分批处理。

I wrote a 4th test, I set the batch size to 10, then alternated when i changed from TestClass1 to TestClass2 so that I was doing 5 of TestClass1 and then 5 of TestClass2, to hit the batch size. 我编写了第4个测试,我将批处理大小设置为10,然后在从TestClass1更改为TestClass2时进行更改,以便我先执行5个TestClass1,然后再执行5个TestClass2,以达到批处理大小。

This pushed out batch's of 5 in the order they were processed. 这按处理顺序推出了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();
    }
}

Then I changed it to insert 3 at a time instead of 5. The batch's were in multiples of 3, so what must be happening is the batch size allows a batch of 1 type to go to specified amount, but groups only the same type together. 然后,我将其更改为一次插入3而不是5。批次是3的倍数,因此必须发生的是,批次大小允许1种类型的批次达到指定的数量,但仅将相同类型分组。 While alternating causes separate insert statements. 交替时会导致单独的插入语句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM