Grails / hibernate Eager Fetching似乎被忽略了

时间:2012-08-10 13:23:56

标签: hibernate grails

我正在解决一些性能问题,这些问题似乎与重复调用数据库有关(数个对象加载了几个子对象)。

问题似乎是尽管急切地加载关系(并且通过记录hibernate SQL确认对象实际上是急切地加载),但每次都会从数据库中提取它们。

我的直觉是询问是否有办法告诉grails / hibernate在内存中使用该对象而不是在我肯定它已经在内存中时返回数据库? < / p>

但这可能是错误的问题。


举例说明正在发生的事情。我的域类Parent定义:

static hasMany = [children: Child]
static mapping = {children fetch:'select'}

可能是fetch:'eager'...我尝试了两种方式,不确定哪个生成下面的日志结果,但显然是急切地获取数据。

我做的第一件事是:

def results = Parent.executeQuery(“从父p中选择不同的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 }
}

这就是问题所在。跨内循环的每次迭代,记录另一个hibernate查询,通过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%确定),因为它正在执行数千次读取。关于如何正确使用内存对象或加载数据的不同方式的任何想法都非常受欢迎。

2 个答案:

答案 0 :(得分:0)

我发现在fetch中设置mapping不足以让grails使用渴望获取。虽然在gorm手册中没有提到,但还有另一个属性fetchMode似乎是必要的。尝试将此添加到您的域类:

static fetchMode = [children: 'eager']

答案 1 :(得分:0)

对于那些意识到我必须做错事的人来说,这应该不足为奇......我做错了什么。该对象正在缓存,但在子例程中调用了parent.refresh()。看起来刷新执行多个查询来加载子对象,一旦刷新被删除我不再看到额外的查询,但似乎刷新应该执行与初始加载相同的单一查询而不是查询孩子的对象。我的代码中可能还有其他错误,我没有完全调试。