提高nHibernate数据访问层的性能

时间:2010-04-18 13:49:27

标签: .net wcf performance nhibernate data-access-layer

我正在努力提高现有Asp.Net Web应用程序的DataAccess Layer的性能。场景是。

  1. 它是Asp.Net中基于Web的应用程序。
  2. DataAccess层使用NHibernate 1.2构建,并公开为WCF服务。
  3. Entity类标有DataContract。
  4. 不使用延迟加载,并且由于关系的急切获取,在内存中加载了大量数据库对象。对数据库的命中率也不高。例如,我使用NHProfiler对应用程序进行了分析,并且大约有50多个sql调用使用主键加载其中一个Entity对象。
  5. 我也不能像现有的实时应用程序那样更改代码,而根本没有NUnit测试用例。
  6. 我可以在这里得到一些建议吗?

    编辑1:我尝试过使用延迟加载,但问题是由于实体也用作DataContract,它会在序列化期间触发延迟加载。 使用DTO对象是一种选择,但这是一个巨大的变化,因为没有任何实体是巨大的。如果没有测试用例,这将需要大量的手动测试工作。

    编辑2:该项目是长期编写的,没有编写单元测试的灵活性。例如 实体本身包含CRUD操作并使用NHibernate Session。

    class SampleEntity : ICrudOperation
    {
       //fields and properties
    
       public IList<SampleEntity> Update()
        {
    
           //perform business logic (which can be huge and call the ICrudOperation of 
           //other entities
    
           ISession session = GetSessionFromSomewhere();
           session.Update(this); 
    
        }
    
    }
    

    这只是Update的一个例子。大约有400个实体是相互依存的。有没有办法为此

    编写单元测试

5 个答案:

答案 0 :(得分:3)

这似乎可以改善这里的架构。

主要问题似乎是正在读取大量数据。是否需要读取所有这些数据?例如,如果实体A具有急切加载的子元素B的列表,但是仅在页面上显示来自实体A的字段,则仅需要读取实体A.如果页面上显示所有内容,请考虑重新设计页面,以便您必须导航到其他页面才能查看实体B数据。

假设您只显示来自实体A的数据或者可以重新设计网站来执行此操作,那么第一件事就是打开子实体的延迟加载,这样您只需要读取它们如果你真的需要这些数据。其次,如果您继续返回实体本身,则启用延迟加载将不起作用,因为当序列化程序序列化您的数据时,子实体仍将被读取。您需要引入一些数据传输对象(DTO)以通过线路传递数据。这些将与您的实体类似,但只包含您实际要在网页上使用的数据的字段。然后,您需要将实体转换为DTO,这意味着您将不会访问您不需要的子实体列表,并且配置了延迟加载,将无法读取数据。

值得研究升级到最新版本的NHibernate,虽然没有单元测试,这可能会让人感到恐惧,但绝对值得。

引入二级缓存可能会产生很小的影响,因为当您在分布式环境中获得大量点击时,这确实会产生影响。您首先要解决更多基本问题。

答案 1 :(得分:3)

建议1

  1. 启用延迟加载
  2. 使用 习惯 的 NhibernateDataContractSerializerSurrogate 在它们出现之前删除代理 通过WCF(check out Allan Ritchie's reply here
  3. 发送

    此组合将减少初始SQL连接的数量,并减小对象图的大小。

    然而,这将导致下一个问题:

    您的消费者/客户无法访问所有数据。他们需要多次调用服务器来检索子对象/集合。

    可以尝试预测需要哪些子对象/集合(并且急切地加载它们),但这可能是一项繁琐的练习。一个更简单的选择是检查空对象/集合(即在消费者处),并调用服务器来获取其他数据。

    建议2

    您的SQL JOIN缓慢吗?您可以尝试使用 fetch = select 替换 fetch = join ,看看是否加快了速度。

    建议3

    确定在SQL中花费的时间,与通过网络发送数据所花费的时间相比较。您可以考虑在通过网络发送之前压缩对象图。

    建议4

    在将对象图表返回给使用者之前,使用您自己的自定义延迟加载代理 交换所有Nhibernate惰性代理。您的自定义代理将通过WCF / Web服务延迟加载数据(而不是调用数据库)。我在富客户端上使用这种技术取得了一些成功。

    理论上,这应该允许您的客户端代码保持原样。 There's a thread here沿着这些方向。

    希望有所帮助。

答案 2 :(得分:2)

也许首先你应该切换到NHibernate的最新稳定版本(2.1.2,AFAIK),虽然我自己更喜欢使用3.0 alpha版本。后来的版本往往比以前的版本具有更高的稳定性和性能。我认为NHibernate的API向后兼容性足以实现这一目标。

所以,我推荐的解决方案是:

如果你真的需要加载,那么用于返回对象和完整对象图的查询数量仍然很大,但不要担心,有希望!< / p>

NHibernate是一个企业级的ORM,这意味着它可以很好地扩展。它可以针对各种场景采用各种缓存策略。

它具有以下内部缓存:

  • 实体
  • 集合
  • 查询
  • 时间戳

它有两个层次:

  • 第一级缓存:缓存单个ISession实例的内容。它默认为ON。
  • 二级缓存:缓存来自同一ISessionFactory的所有内容的内容。默认为OFF。

以上描述对我来说非常基础,但这正是您所需要的。您可以在nhibernate.infoAyende's blogseveral questions in StackOverflow以及其他地方的varios上找到有关该主题的更多信息。

你需要做两件事:

  • 确保所有ISession来自同一ISessionFactory
  • 启用二级缓存(以上链接可帮助您)

使用这种方法可以获得许多优势,但主要是因为您加载的所有实体都将被缓存,因此只需要从数据库中请求一次。之后,他们将来自缓存。这减少了到数据库的往返次数,非常

答案 3 :(得分:1)

除了其他人的建议之外,您是否考虑过使用NHibernate Profiler对应用进行概要分析? (有30天的试用期)

  

NHibernate Profiler是一个实时的   可视化调试器允许开发   团队获得宝贵的见解和   透视他们的用法   NHibernate的。该产品是架构的   来自许多顶级的输入   NHibernate内的行业领导者   社区。警报以a表示   简明的代码审查方式表明   你的滥用模式   应用。精简你的   我们努力纠正滥用行为   提供有问题代码的链接   触发警报的部分。

答案 4 :(得分:0)

在NHibernate内部配置缓存策略....