这种 Hibernate 方法效率很低吗?
Is this Hibernate method very inefficient?
此函数是我正在编写的一个 Hibernate 程序的一部分,用于为大学财务系统执行一些后端批量处理。它在程序执行时被调用了数十万次,这些调用是程序中最大的一次耗时。目前我想不出一个合理的方式来减少调用它的频率。
此函数以财政年度支付期间 ("fypper") 和该期间的一周作为参数,returns 一个存储年份、学期的结构 ("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;
}
有什么我可以做的吗simpler/faster?
最简单和最明显的优化如下:
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)但是只有当有相对较少的缓存时才有效fypper|week
组合。
乍一看:
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
中,以随后避免了数以千计的数据库往返。
请注意,因为 fypper
和 week
实际上形成了一个(字符串)复合键,您可以构建单个 Map<String, AidYearTerm>
,其中键可以是,例如 year + "_" + week
。然后你的 FypperTermInfo (String fypper, String week)
将只是 return aidYearCacheMap.get(fypper + "_" + week);
和 voilà :)
这看起来非常简单 select,所以我认为这可能更像是一个围绕确保 Oracle 运行 高效运行的问题(特别是因为它 运行 成千上万每天几次)。对于这个查询,你看到什么样的解释计划?是否有完整的 table 扫描?您可能需要索引 sfa_fws_calendar table,或者如果已经有索引,请更改适当的索引并重新计算索引统计信息。
例如,类似这样的内容可能有助于更新名为 index_name:
的现有索引
ALTER INDEX index_name REBUILD COMPUTE STATISTICS;
此函数是我正在编写的一个 Hibernate 程序的一部分,用于为大学财务系统执行一些后端批量处理。它在程序执行时被调用了数十万次,这些调用是程序中最大的一次耗时。目前我想不出一个合理的方式来减少调用它的频率。
此函数以财政年度支付期间 ("fypper") 和该期间的一周作为参数,returns 一个存储年份、学期的结构 ("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;
}
有什么我可以做的吗simpler/faster?
最简单和最明显的优化如下:
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)但是只有当有相对较少的缓存时才有效fypper|week
组合。
乍一看:
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
中,以随后避免了数以千计的数据库往返。
请注意,因为 fypper
和 week
实际上形成了一个(字符串)复合键,您可以构建单个 Map<String, AidYearTerm>
,其中键可以是,例如 year + "_" + week
。然后你的 FypperTermInfo (String fypper, String week)
将只是 return aidYearCacheMap.get(fypper + "_" + week);
和 voilà :)
这看起来非常简单 select,所以我认为这可能更像是一个围绕确保 Oracle 运行 高效运行的问题(特别是因为它 运行 成千上万每天几次)。对于这个查询,你看到什么样的解释计划?是否有完整的 table 扫描?您可能需要索引 sfa_fws_calendar table,或者如果已经有索引,请更改适当的索引并重新计算索引统计信息。
例如,类似这样的内容可能有助于更新名为 index_name:
的现有索引ALTER INDEX index_name REBUILD COMPUTE STATISTICS;