我写了一个应用程序,该应用程序会抓取互联网广播播放列表,然后将其保存到数据库中。为了了解休眠,我将应用程序迁移为使用休眠,但是与其他尝试相比,在执行SELECT ... WHERE查找时,我发现性能下降很大。在我的python sqlite原型中,相同的过程(获取大约17,000个曲目(按播放它们的程序以及播放它们的人分组))花费了150ms,而使用apache db utils的最初的Java版本花费了250ms,与我相比(可能太恐怖了) )的休眠版本,大约需要1100毫秒。
@Override
public DJAllProgrammes getAllProgrammesFromDJ(Collection<String> names) {
DJAllProgrammes djAllProgrammes = new DJAllProgrammes();
session.beginTransaction();
List<Presenter> result = session.createQuery("from Presenter p WHERE p.presenter_name in :names", Presenter.class)
.setParameterList("names", names)
.getResultList();
for (Presenter presenter : result) {
int presenter_id = presenter.getPresenter_id();
List<Programme> programmes = session
.createQuery("from programme prog WHERE prog.presenter_origin_id = :pres_orig_id", Programme.class)
.setParameter("pres_orig_id", presenter_id)
.getResultList();
for (Programme programme : programmes) {
//this is the critical performance death zone
List<Track> tracksOnThisProgramme = session
.createQuery("FROM track t WHERE t.programme.programme_id in :progIds", Track.class)
.setParameter("progIds", programme.getProgramme_id())
.getResultList();
djAllProgrammes.addProgramme(new ProgrammeData(presenter.getPresenter_name(), programme.getDate(), tracksOnThisProgramme));
}
}
session.getTransaction().commit();
return djAllProgrammes;
}
调试信息:
INFO:会话指标
{
33339 nanoseconds spent acquiring 1 JDBC connections;
71991 nanoseconds spent releasing 1 JDBC connections;
12938819 nanoseconds spent preparing 258 JDBC statements;
88949720 nanoseconds spent executing 258 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
4671332 nanoseconds spent executing 1 flushes (flushing a total of 9130 entities and 0 collections);
599862735 nanoseconds spent executing 258 partial-flushes (flushing a total of 1079473 entities and 1079473 collections)
}
环顾互联网,我看到了一个建议,该建议基于交易中有太多实体以至于无法使用“分页和较小的批次增量”-我可以找到有关什么是“分页”的信息,而不是“使用较小的批次增量”的信息意思是
我有点束手无策,在使用Apache DB Utils(轻量级的jdbc包装器)的情况下,此应用程序具有出色的性能,几乎可以完成相同的操作,而且我非常无知,甚至不知道要搜索什么加快速度。帮兄弟出去吗
也使用了bean(持久性实体...?)答案 0 :(得分:1)
通常所说的:OR-Mapper允许您为另一个实体建模。 我看到您的代码中的演示者具有许多程序,它们之间存在一些1:N关系。
类名“ Programme”可能是第一个错误,因为它是复数形式。最好在“ Presenter”类中使用“ Programm”并为@OneToMany关系建模。
这样做时,您只需触发一个休眠查询。找到的“ Presenter”类型的实体将包含“ Programm”的列表/集。遍历实体,并将其转换为返回值'DJAllProgrammes',该返回值应仅包含纯值(dto),而不包含对实体的引用。即将实体映射到dto。
答案 1 :(得分:0)
为此任务使用像Hibernate这样的ORM总是比直接使用JDBC层的原型版本中的db utils慢。考虑发生了什么事
List<Presenter> result = session.createQuery("from Presenter p WHERE p.presenter_name in :names", Presenter.class)
.setParameterList("names", names)
.getResultList();
解析查询之后,解析对象,然后names
的大小确定将扩展为(?,?,?...)
的参数的数量。
然后发送查询,结果输入后,每个查询都会创建两个副本。在结果列表中将为您提供一个,在内部将其保留以检查更改的一个。
for (Presenter presenter : result) {
int presenter_id = presenter.getPresenter_id();
List<Programme> programmes = session
.createQuery("from programme prog WHERE prog.presenter_origin_id = :pres_orig_id", Programme.class)
.setParameter("pres_orig_id", presenter_id)
.getResultList();
在这里,我们又发生了同样的事情,只是实际情况更糟。您不是在重复使用查询,而是在每个循环上创建一个新查询,然后将其丢弃。
嵌套循环中发生了同样的事情。
同样,如果presenter.getPresenter_id()返回一个Integer
对象而不是原始的int
,则表示您正在进行不必要的拆箱,然后在.setParameter("pres_orig_id", presenter_id)
调用中重新装箱。如果该方法返回一个Integer对象,则将其更改为Integer presenter_id
。但是,如果它是原始的int
,则没有必要,但这不会造成伤害,因为唯一的用法是作为对象传递。您甚至可以直接在setParameter
中使用它。
因此,总的来说,当您将createQuery调用带出循环时,您会得到它。
@Override
public DJAllProgrammes getAllProgrammesFromDJ(Collection<String> names) {
DJAllProgrammes djAllProgrammes = new DJAllProgrammes();
session.beginTransaction();
List<Presenter> result = session.createQuery("from Presenter p WHERE p.presenter_name in :names", Presenter.class)
.setParameterList("names", names)
.getResultList();
TypedQuery<Programme> progByPresenterOrigin = session
.createQuery("from programme prog WHERE prog.presenter_origin_id = :pres_orig_id", Programme.class);
TypedQuery<Track> trackByProgrammeId = session
.createQuery("FROM track t WHERE t.programme.programme_id in :progIds", Track.class)
for (Presenter presenter : result) {
List<Programme> programmes = progByPresenterOrigin
.setParameter("pres_orig_id", presenter.getPresenter_id())
.getResultList();
for (Programme programme : programmes) {
//this is the critical performance death zone
List<Track> tracksOnThisProgramme = trackByProgrammeId
.setParameter("progIds", programme.getProgramme_id())
.getResultList();
djAllProgrammes.addProgramme(new ProgrammeData(presenter.getPresenter_name(), programme.getDate(), tracksOnThisProgramme));
}
}
session.getTransaction().commit();
return djAllProgrammes;
}