我正在运行Hibernate 4.1,在Oracle 12c之上运行在Hikari池之上的Javassist运行时检测。 JDK是1.7。
我有一个在数据库上运行得非常快的查询,并在Hibernate中获取大约500个实体。根据JProfiler,查询运行时非常小,大约11毫秒,但总共Query.list
运行大约7秒。
我尝试删除所有过滤器,它表明大部分时间花在Javaassist和其他与Hibernate相关的反射调用上(如AbstractProxyHandler
等)。我读到反射开销应该很小,但似乎不是,而且看起来它太多了。
你能否告诉我这里可能出现什么瓶颈?
答案 0 :(得分:0)
确保您要检索的对象没有作为SELECT懒惰地获取的子对象,而不是热切地作为JOIN。这可能导致称为SELECT N + 1的行为,其中Hibernate最终运行查询以从其各自的表中获取500个对象,然后对每个对象进行额外的查询以获取子对象。如果您有4个或5个关系作为每条记录的SELECT语句被提取,并且您有500条记录,那么突然您将运行大约2000个查询以获取列表。
我建议打开Hibernate的SQL日志记录,看看它正在运行哪些查询。如果在您获取列表时转储了很长的SELECT查询列表,请查看您的映射文件以查看您的关系是如何设置的。尝试将它们调整为fetch =" join"并查看这些查询是否消失以及性能是否有所改善。
以下是一些可能相关的Stack Overflow问题,可能会提供更具体的细节。
Hibernate FetchMode SELECT vs JOIN
What is N+1 SELECT query issue?
关于剖析器和其他工具的其他注意事项。通常,在追踪性能问题时,特定的代码块将显示为花费最多时间的位置。人们倾向于跳到的常见结论是所讨论的代码块很慢。在您的情况下,您似乎正在观察Hibernate的反射代码,因为它是花费时间的地方。考虑到这段代码本身可能实际上并不慢,这是非常重要的,但由于算法复杂性,因此被频繁调用是花费时间的地方。我发现在许多问题中,序列化或反射出现变慢,当现实是代码用于与外部资源通信,并且该资源被调用1000次时它应该只被称为少数。进行1000次查询以获取列表将导致您的抽样显示在处理这些查询的代码中花费了大量时间。注意不要因为代码设计/配置问题而经常调用的代码错误。问题很可能不在于休眠使用反射,因为反射通常不会在几秒钟内变慢。