我正在解决一些似乎与重复调用数据库有关的性能问题(几千个对象加载每个对象都有几十个子对象)。
问题似乎是,尽管急切地加载关系(并通过记录休眠 SQL 确认对象实际上是急切地加载的),但它们仍然每次都从数据库中获取。
我的直觉是问是否有办法告诉 grails/hibernate 使用内存中的对象,而不是当我确定它已经在内存中时返回数据库?
不过,这可能是个错误的问题。
举一个具体的例子来说明正在发生的事情。我的域类 Parent 定义:
static hasMany = [children: Child]
static mapping = {children fetch:'select'}
可能是 fetch:'eager'... 我尝试了两种方法,不确定哪个生成了下面的日志结果,但它显然是急切地获取数据。
我做的第一件事是:
def results = Parent.executeQuery("SELECT distinct p from Parent p WHERE ... complex where 子句")
查看日志,这并没有急切地加载子关系,但这并不是非常意外,也不是真正的杀手。接下来我遍历父母:
for(Parent parent : results)
{ blah blah }
循环的每次迭代都表明 hibernate 正在通过 id 查询 Parent p 并且似乎正在急切地加载所有子关系。日志片段:
select
parent0_.id as id4_4_,
parent0_.version as version4_4_,
parent0_.date_created as date3_4_4_,
child1_.parent_id as parent6_6_,
child1_.id as id6_,
child1_.child_idx as idx9_6_,
child1_.id as id22_1_,
child1_.version as version22_1_,
...continues for all fields.
注意:我不知道为什么它两次映射 id 字段。
伟大的!它急切地加载我需要的子对象!在上面的父循环中,然后我遍历子循环:
for(Parent parent : results)
{
for(Child child : parent.children)
{ blah blah }
}
这就是问题所在。内部循环的每次迭代,都会记录另一个休眠查询,按 id 加载对象。日志片段:
select child0_.id as id22_1_,
child0_.version as version22_1_,
child0_.parent_id as parent6_22_1_,
child0_.sequence_number as sequence8_22_1_,
...and all the rest
这些不必要的负载绝对会扼杀我的性能(至少,这似乎是瓶颈,我不能 100% 确定),因为它正在执行数千次读取。非常感谢有关如何正确使用内存对象或加载数据的不同方式的任何想法。