首页 文章

提高nHibernate数据访问层的性能

提问于
浏览
4

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

  • 它是Asp.Net中基于Web的应用程序 .

  • DataAccess层使用NHibernate 1.2构建,并作为WCF服务公开 .

  • Entity类标有DataContract .

  • 没有使用延迟加载,并且由于关系的急切获取,在内存中加载了大量的数据库对象 . 对数据库的命中率也不高 . 例如,我使用NHProfiler对应用程序进行了分析,并且大约有50个sql调用使用主键加载其中一个Entity对象 .

  • 我也不能像现有的实时应用程序那样更改代码,根本没有NUnit测试用例 .

我可以在这里得到一些建议吗?

编辑1:我尝试过使用Lazy加载,但问题是由于Entity也用作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 回答

  • 2

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

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

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

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

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

  • 1

    建议1

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

    However ,这将导致下一个问题:

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

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

    建议2

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

    建议3

    确定 time being spent in SQL ,与 send data over the wire 所用的时间相对应 . 您可以考虑在通过网络发送之前压缩对象图 .

    建议4

    Swap any Nhibernate lazy proxies with your own custom lazy-load proxies ,在将对象图返回给使用者之前 . 您的自定义代理将通过WCF / Web服务延迟加载数据(而不是调用数据库) . 我使用它取得了一些成功富客户端的技术 .

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

    希望有所帮助 .

  • 0

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

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

    如果你真的需要加载,那么用于返回一个对象和完整对象图的查询数量仍然很大,但不要担心, there is hope

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

    它具有以下内部缓存:

    • 实体

    • 收藏

    • 查询

    • 时间戳

    它有两个级别:

    • 第一级缓存:缓存单个 ISession 实例的内容 . 它默认为ON .

    • 二级缓存:缓存来自同一 ISessionFactory 的所有内容 . 默认为OFF .

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

    你需要做两件事:

    • 确保所有 ISession 来自同一个 ISessionFactory

    • 启用二级缓存(以上链接可以帮助您)

    你'll gain many advantages with this approach, but mostly, because all the entities you ever loaded will get cached, it will only be necessary to request them from the database once. After that, they'来自缓存 . 这减少了到数据库的往返次数 vastly .

  • 3

    除了其他人的建议之外,您是否看过使用NHibernate Profiler分析您的应用程序? (有30天的试用期)

    NHibernate Profiler是一个实时可视化调试器,允许开发团队获得有关NHibernate使用的宝贵见解和观点 . 该产品的架构是来自NHibernate社区内许多顶级行业领导者的意见 . 警报以简明的代码审查方式呈现,表明您的应用程序滥用的模式 . 为了简化您纠正错误操作的工作,我们提供了触发警报的有问题代码部分的链接 .

  • 3

    在NHibernate中配置缓存策略....

相关问题