2015-02-23 134 views
0

这个函数是我写的一个Hibernate程序,用于为大学金融系统做一些后端批量处理。程序执行时会被调用数十万次,这些调用是程序中最大的单次调用。目前我想不出一种合理的方式来减少它的使用次数。这种Hibernate方法效率很低吗?

此函数以财政年度支付期(“fypper”)和该期间的一周为参数,并返回一个构造(“AidYearTerm”),该构造存储支付周期所在的年份,学期和期限英寸

public AidYearTerm FypperTermInfo (String fypper, String week) { 

    sfa_fws_calendar aidYear = new sfa_fws_calendar();  

    TypedQuery<sfa_fws_calendar> query = manager.createQuery("FROM sfa_fws_calendar cal " 
      + "WHERE cal.id.fypper = ?1 AND cal.id.week_num = ?2",sfa_fws_calendar.class); 
    query.setParameter(1, fypper); 
    query.setParameter(2, week); 

    List<sfa_fws_calendar> aidYearList = query.getResultList(); 

    if(!aidYearList.isEmpty()) { 
     aidYear = query.getSingleResult(); 
    } 
    else { 
     aidYear.setFWS_AID_YR("9999"); 
     aidYear.setSEM("NOTSET"); 
     aidYear.setTERM("NOTSET"); 
     ErrorOut("Could not find term info for "+fypper); 
    } 
    DebugOut("found aid year "+aidYear.getFWS_AID_YR()+", term "+aidYear.getTERM()); 

    AidYearTerm aidYearTerm = new AidYearTerm(aidYear.getFWS_AID_YR(),aidYear.getTERM(),aidYear.getSEM()); 
    return aidYearTerm; 

} 

有什么我可以做,使这更简单/更快?

+0

“被调用几十万次” - 数据库查询,执行数十万次?如果除了极大地减少这个数字之外没有太多的改进,我们不会感到惊讶。 – JimmyB 2015-02-23 16:16:40

+0

顺便说一下,数据库中有多少年和几周的组合? - 如果它不是数百万,我认为它不是,它应该很容易读取一次,例如存储在一个'HashMap'中,然后操作这个缓存的数据。 – JimmyB 2015-02-23 16:21:32

+0

约有11,000种组合。在将它们存储在散列表中并参考它而不是重新查询之后,过去需要两个小时的过程现在大约需要十五分钟。谢谢! – 2015-02-23 18:42:06

回答

0

乍一看:

List<sfa_fws_calendar> aidYearList = query.getResultList(); 

if(!aidYearList.isEmpty()) { 
    aidYear = query.getSingleResult(); // <========= DON'T!!!!! 
} 

Query.getSingleResult()再次运行相同的查询!

用途:

List<sfa_fws_calendar> aidYearList = query.getResultList(); 

if(!aidYearList.isEmpty()) { 
    aidYear = aidYearList.get(0); 
} 

编辑:

假设你没有数以百万计的年份和周键记录,似乎可行的读取sfa_fws_calendar所需的所有数据到内存中只有一次,例如转换为Map,以便随后避免数千次往返数据库。

需要注意的是,因为fypperweek实际上形成(串)组合键,你可以建立一个Map<String, AidYearTerm>,其中的键可以,例如,year + "_" + week。然后你的FypperTermInfo (String fypper, String week)只会return aidYearCacheMap.get(fypper + "_" + week);和voilà:)

0

最简单和最明显的优化将是这样的:

static final TypedQuery<sfa_fws_calendar> query = manager.createQuery("FROM sfa_fws_calendar cal " 
     + "WHERE cal.id.fypper = ?1 AND cal.id.week_num = ?2", sfa_fws_calendar.class); 

public AidYearTerm FypperTermInfo(String fypper, String week) { 

    //... 
    query.setParameter(1, fypper); 
    query.setParameter(2, week); 

    List<sfa_fws_calendar> aidYearList = query.getResultList(); 

不知道叫createQuery的开销,但是这肯定只能得到一次发生。然后,如果所有东西仍然在爬行(这很可能),那么可以考虑某种形式的缓存(可能为ehcache),但只有在组合数量相对较少的情况下才有效。

0

这看起来像一个非常简单的选择,所以我认为这可能是更多的问题围绕确保Oracle有效地运行它(特别是因为它每天运行数千次)。你对这个查询看到了什么样的解释计划?有没有全表扫描?您可能需要对sfa_fws_calendar表进行索引,或者如果已经存在索引,请更改适当的索引并重新计算索引统计信息。

例如,这样的事情可能会帮助更新现有的索引称为INDEX_NAME:

ALTER INDEX index_name REBUILD COMPUTE STATISTICS;