NHiberNate性能问题

很多人对于ORM的性能有偏见, 认为其性能会很差. 当然在大部分情况下, 查询的性能可以根据检索策略, 延迟加载, 二级缓存等等进行调优, 这个我就不谈了, 因为有大量的文章涉及到这点. 我这篇文章, 主要是想探讨另外一个方面的性能问题, 大数据量批量操作方面的.

对于一般有经验的ORM使用者来说, 一提到大数据量操作一般也就会说, 嗯, 这个嘛, ORM对此确实效率低下, 我们一般采用直接ADO.net. 确实是这样的. 如果是批量删除. 用ORM去做绝对是效率低下的. 那么批量插入呢? 我这边做了一个测试. 来证明使用ORM并对其进行性能调优, 有可能比直接使用SQL速度更快.

我定义了一个简单的实体, 只有两个属性, 一个是ID, 一个是Description. ID是GUID类型. 我没有使用NH的配置文件对其进行映射, 改为使用Castle AR的attribute. 其他方面均和NH一致. 另外我定义了一个UnitOfWork的类, 用来管理session这些东西. 大家可以忽略.

我这边只测试了插入60000条数据. 分别使用了纯粹的ADO.net, 默认情况下的NH, 以及设置了Batch_Size的NH, 最后是NH2里面最新引入的StatelessSession.

 

测试的结果可能会给大家一个惊奇. 我的机器是 T61p, 配置为 CPUT7250, 2G RAM. 不同机器时间可能不一样.

ADO.NET:  00:00:12.1994805

NH: 00:00:20.0452743

NH With Batch_Size 100: 00:00:08.8320574

NH With StatelessSession: 00:00:04.8881699

 

可以看到. 在默认情况下, NH插入这样简单的一个对象, 会比ADO.NET慢上许多. 耗时快2倍了. 的确很慢. 但是如果设置Batch_size为100之后, 耗时居然只有直接ADO.net的2/3. 如果使用了StatelessSession, 更是只有1/3左右.

 

当然, 你可能会说, 我写SQL也可以进行优化, 也可以100条sql一起执行, 这样性能也会大大提高. 但是. 我们可以看到. NH的性能优化是非注入性的, 只需要调整一下配置文件即可. 而不需要对代码进行修改.  几乎所有SQL可以调优的方法, ORM基本都可以使用, 但是相对于SQL, ORM还有更多更高层次的调优方法.

 

自此, 所谓NH的性能比直接ADO.NET慢的说法也不攻自破.

[ActiveRecord]
    public class GuidTestObject
    {
        [PrimaryKey(PrimaryKeyType.GuidComb)]
        public virtual Guid Id { get; set; }

        [Property]
        public virtual string Description { get; set; }
    }

    [TestFixture]
    public class PerformanceTest : DatabaseTestFixtureBase
    {
        [SetUp]
        public void TestInitialize()
        {
            InitializeFramework();
        }

        [TearDown]
        public void TestCleanup()
        {
            DisposeUnitOfWork();
        }

        private IList<GuidTestObject> CreateObjects(int count)
        {
            IList<GuidTestObject> list = new List<GuidTestObject>(count);
            for (int i = 0; i < count; i++)
            {
                list.Add(new GuidTestObject{Description = Guid.NewGuid().ToString()});
            }

            return list;
        }

        [Test]
        [TestCategory("Performance")]
        public void Insert60000DataWithADO()
        {
            // My result is 00:00:12.1994805 on a T7250, 2g laptop machine.
            var watch = new Stopwatch();
            watch.Start();
            using (var transaction = UnitOfWork.Current.BeginTransaction())
            {
                for (int i = 0; i < 60000; i++)
                {
                    Repository<GuidTestObject>.ExecuteNoneQuery("insert into GuidTestObjects values(@Id, @Description)",
                                                                new[]
                                                                    {
                                                                        new Parameter("Id", Guid.NewGuid()),
                                                                        new Parameter("Description",
                                                                                      Guid.NewGuid().ToString())
                                                                    });
                }

                transaction.Commit();
            }
            watch.Stop();

            Console.WriteLine(watch.Elapsed);
        }

        [Test]
        [TestCategory("Performance")]
        public void Insert60000DataWithNHBatchSize1()
        {
            // My result is 00:00:20.0452743 on a T7250, 2g laptop machine. show_sql=false, adonet.batch_size=1

            var objects = CreateObjects(60000);
            var watch = new Stopwatch();
            watch.Start();
            using (var transaction = UnitOfWork.Current.BeginTransaction())
            {
                foreach (var o in objects)
                {
                    Repository<GuidTestObject>.Save(o);
                }

                transaction.Commit();
            }
            watch.Stop();

            Console.WriteLine(watch.Elapsed);
        }

        [Test]
        [TestCategory("Performance")]
        public void Insert60000DataWithNHBatchSize100()
        {
            // My result is 00:00:08.8320574 on a T7250, 2g laptop machine. show_sql=false, adonet.batch_size=100

            var objects = CreateObjects(60000);
            var watch = new Stopwatch();
            watch.Start();
            using (var transaction = UnitOfWork.Current.BeginTransaction())
            {
                foreach (var o in objects)
                {
                    Repository<GuidTestObject>.Save(o);
                }

                transaction.Commit();
            }
            watch.Stop();

            Console.WriteLine(watch.Elapsed);
        }

        [Test]
        [TestCategory("Performance")]
        public void Insert60000DataWithNHWithStatelessSession()
        {
            // My result is 00:00:04.8881699 on a T7250, 2g laptop machine. show_sql=false, adonet.batch_size=100

            var objects = CreateObjects(60000);
            var watch = new Stopwatch();
            watch.Start();

            using (var session = UnitOfWork.GetSessionFactoryFor(typeof(GuidTestObject)).OpenStatelessSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    foreach (var o in objects)
                    {
                        session.Insert(o);
                    }

                    transaction.Commit();
                }
            }
            watch.Stop();

            Console.WriteLine(watch.Elapsed);
        }

        
    }

http://home.cnblogs.com/group/topic/6221.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值