Grails/hibernate Eager提交似乎被忽略
我正在处理一些性能问题,这些问题看起来与重复调用数据库(几千个对象,每个都有几十个子对象)有关。Grails/hibernate Eager提交似乎被忽略
问题似乎是,尽管加载关系(并确认对象实际上是通过记录hibernate SQL实际加载的),但它们仍然每次都从数据库中获取。
我的直觉是问我是否有办法告诉grails/hibernate在内存中使用这个对象,而不是回到数据库,因为我肯定它已经在内存中了?
虽然这可能是错误的问题。
给出一个具体的例子。我的域类父定义:
static hasMany = [children: Child]
static mapping = {children fetch:'select'}
可能已经获取:“渴望” ......我想两者兼得,不知道哪个产生下面的日志结果,但它显然急切地获取数据。
我做的第一件事是:
高清结果= Parent.executeQuery(“从父p选择不同的P其中......复杂的where子句”)
查看日志,这不急切地加载孩子的关系,但这并不是非常意外,并且在这一点上并不是真正的杀手。接下来,我遍历整个家长:
for(Parent parent : results)
{ blah blah }
循环的每次迭代显示,Hibernate是根据ID查询父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%确定),因为它的执行数千读取。非常感谢您对如何正确使用内存对象或不同方式加载数据的任何想法。
我发现在mapping
中设置fetch
不足以让grails使用预先抓取。虽然它在gorm手册中没有提到,但还有另外一个属性fetchMode
似乎是必要的。尝试添加给你的域类:
static fetchMode = [children: 'eager']
这应该是毫不奇怪谁意识到,我必须做一些错误的...我做错了什么人。该对象正在被缓存,但是在子例程中调用了parent.refresh()。看起来刷新正在执行多个查询来加载子对象,一旦刷新被删除,我不再看到额外的查询,但似乎刷新应该执行与初始加载相同的单一查询而不是查询孩子的对象。我的代码中可能还有其他错误,我没有完全调试。
感谢您的建议,任何事情都值得一试,当你卡住了。 – Trebla 2012-08-15 12:31:08