Java 获取集合子集的策略

Java 获取集合子集的策略,java,performance,hibernate,Java,Performance,Hibernate,我的应用程序可以在有限的时间窗口内访问会话,在此期间,它必须将数据库中的数据提取到内存中,然后只使用内存中的数据来服务请求 数据模型是一个简单的一对多关联,例如: <class name="com.foo.Road" table="road"> <id name="oid" column="oid"/> <map name="carCountMap" fetch="subselect"> <key column="roa

我的应用程序可以在有限的时间窗口内访问会话,在此期间,它必须将数据库中的数据提取到内存中,然后只使用内存中的数据来服务请求

数据模型是一个简单的一对多关联,例如:

<class name="com.foo.Road" table="road">
    <id name="oid" column="oid"/>

    <map name="carCountMap" fetch="subselect">
        <key column="road_oid" foreign-key="oid"/>
        <index column="time_oid" type="long" />
        <one-to-many class="com.foo.CarCount" />
    </map>

    <map name="truckCountMap" fetch="subselect">
        <key column="road_oid" foreign-key="oid"/>
        <index column="time_oid" type="long" />
        <one-to-many class="com.foo.TruckCount" />
    </map>
</class>
问题是,结果查询返回数百万行,而它应该是10k roads*4 measures per month(weekly)*3 month=~120k。这个查询大约在一个小时内完成,这是荒谬的,因为方法#1(就我而言,加载完全相同的数据)在3分钟内完成

3.将地图定义为惰性,并首先使用条件加载道路,然后运行其他查询以填充集合

    List roadList = session.createCriteria(Road.class).list();

    session.getNamedQuery("fetchCcm").setLong("startDate", startDate).list();
    session.getNamedQuery("fetchTcm").setLong("startDate", startDate).list();

    return roadList;
这将触发正确的查询,但检索到的汽车和卡车计数不会附加到
道路列表中的
道路
对象。因此,当我尝试访问任何道路对象的计数时,我会得到一个
LazyInitializationException

4.将地图定义为惰性,使用
criteria.list()
加载所有道路,迭代过去3个月内的所有测量日期,以便强制加载这些值

我还没有尝试过这个,因为它听起来很笨重,而且我不相信它能摆脱懒洋洋的初始化异常

  • 对于我用这些方法遇到的问题,有什么解决办法吗
  • 有没有更好的方法

    • 我认为你的问题实际上包括两部分:

      • 如何表示域模型中的数据子集
      • 如何获取具有所需性能级别的数据
      关于第一部分,我认为当您试图将数据子集加载到
      Road
      的字段中时,您滥用了域模型

      也许最好将
      道路
      与交通测量之间的关系设置为单向关系,即从
      道路
      类中删除这些地图。这看起来很合理,因为您可能不需要同时使用所有这些数据。然后,您可以创建一个DTO(未映射!)
      RoadStatistics
      ,由
      Road
      和这些交通地图组成,并用您想要的任何数据填充它


      关于问题的第二部分,我认为您需要使用纯SQL进行一些实验,以优化查询,然后将最佳查询转换为HQL或条件。如果您的域模型不限制您加载数据的方式,则可以轻松地完成此转换(请参见第一部分)。也许您需要通过创建一些索引等来优化您的数据库模式。

      在深入研究了更多内容后,看起来这正是我需要的解决方案

      它们基本上提供了一个在集合或类上具有
      where
      属性的构造,并在运行时绑定参数

      在映射文件中,定义过滤器并将其附加到集合:

      <class name="com.foo.Road" table="road">
          <id name="oid" column="oid"/>
      
          <map name="carCountMap" fetch="subselect">
              <key column="road_oid" foreign-key="oid"/>
              <index column="time_oid" type="long" />
              <one-to-many class="com.foo.CarCount" />
              <filter name="byStartDate" condition="time_oid > :startDate" />
          </map>
      
          <map name="truckCountMap" fetch="subselect">
              <key column="road_oid" foreign-key="oid"/>
              <index column="time_oid" type="long" />
              <one-to-many class="com.foo.TruckCount" />
              <filter name="byStartDate" condition="time_oid > :startDate" />
          </map>
      </class>
      
      <filter-def name="byStartDate">
          <filter-param name="startDate" type="long"/>
      </filter-def>
      

      谢谢你的回答。单独加载统计数据,然后在内存中进行映射也是我没有尝试过的一个选项。这很有道理!不过,我认为
      解决方案可能适合我。您认为该解决方案仍然存在滥用的味道吗?@oksayt:如果提供所需的性能级别(即,您不需要手动优化查询),则带有过滤器的解决方案看起来是可行的。
      <class name="com.foo.Road" table="road">
          <id name="oid" column="oid"/>
      
          <map name="carCountMap" fetch="subselect">
              <key column="road_oid" foreign-key="oid"/>
              <index column="time_oid" type="long" />
              <one-to-many class="com.foo.CarCount" />
              <filter name="byStartDate" condition="time_oid > :startDate" />
          </map>
      
          <map name="truckCountMap" fetch="subselect">
              <key column="road_oid" foreign-key="oid"/>
              <index column="time_oid" type="long" />
              <one-to-many class="com.foo.TruckCount" />
              <filter name="byStartDate" condition="time_oid > :startDate" />
          </map>
      </class>
      
      <filter-def name="byStartDate">
          <filter-param name="startDate" type="long"/>
      </filter-def>
      
      session.enableFilter("byStartDate").setParameter("startDate", calculatedStartDateOid);
      return session.createCriteria(Road.class).list();