0

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

问题似乎是,尽管急切地加载关系(并通过记录休眠 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% 确定),因为它正在执行数千次读取。非常感谢有关如何正确使用内存对象或加载数据的不同方式的任何想法。

4

2 回答 2

0

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

static fetchMode = [children: 'eager']
于 2012-08-10T15:42:10.423 回答
0

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

于 2012-08-15T12:33:28.597 回答