[英]hibernate One-to-many association : subselect or eager
In a grails application, i have a relationship that is by default lazy: 在grails应用程序中,我有一个默认为惰性的关系:
class Author{
String name
static mapping = {
books lazy:false
}
}
I have a criteria API query that fetches the Authors. 我有一个提取作者的标准API查询。 When i run the query
当我运行查询
Author.createCriteria().list{
eq("name", "John")
}
i have N+1 subselects for each Author. 我为每个作者有N + 1个子选择。
My second approach is to eager fetch the books just like this: 我的第二种方法是渴望像这样取书:
Author.createCriteria().list{
eq("name", "John")
fetchMode("books", FetchMode.JOIN)
}
In this case, the N+1 select problem does not appear, however i have a JOIN query. 在这种情况下,不会出现N + 1选择问题,但是我有一个JOIN查询。
Which approach is better in terms of performance and optimization ? 在性能和优化方面哪种方法更好?
I think you meant by default eager
instead of lazy
in the first line of the question. 我认为您在问题的第一行默认是
eager
而不是lazy
。
POINT TO REMEMBER 要点
When associations are included in criteria query, they are by default eagerly fetched. 当标准查询中包含关联时,默认情况下会急切获取它们。
In your case you do not need the mapping books lazy:false
in Author
. 在您的情况下,您不需要
Author
的映射books lazy:false
。
In terms of optimization I would vouch for the below approach: 在优化方面,我保证采用以下方法:
class Author {
String name
static hasMany = [books: Book]
static mapping = {
//books lazy:false (DO NOT NEED)
}
}
class Book {
String bookName
//set belongsTo if you need bi-directional one-many
//books gets cascade deleted when author is deleted
//static belongsTo = [author: Author]
}
//Bootstrap
def author1 = new Author(name: "Dan Brown")
def book1 = new Book(bookName: "Da Vinci Code")
def book2 = new Book(bookName: "Angels And Demons")
def book3 = new Book(bookName: "Inferno")
[book1, book2, book3].each {author1.addToBooks(it)}
author1.save(flush: true, failOnError: true)
//Criteria
Author.createCriteria().list{
eq("name", "Dan Brown")
books{
//books are eagerly fetched by default using inner join. No need to specify FetchMode.
}
}
In terms of performance I would not go with the above approach if I have each Author who has wrote 20000 blogs(replace books with blogs). 在性能方面,如果我每个作者都写了20000个博客(用博客替换书籍),我就不会采用上述方法。 Eagerly fetching 20000 blogs for
n
authors will be a performance hit. 急于为
n
作者抓取20000个博客将对性能产生影响。 In this case I would go for lazy fetch (N + 1) route and try to filter out blogs as per my requirement. 在这种情况下,我会选择延迟获取(N + 1)路由,并尝试根据我的要求过滤掉博客。 Something like below:
如下所示:
def author = Author.findByName("Dan Brown")
def books = author.books
//Assume you have a field publishedYear in Book
def booksReleasedIn2013 = author.books.findAll{it.publishedYear == 2013}
def booksReleasedBefore2013 = author.books.findAll{it.publishedYear < 2013}
assert "Inferno" in booksReleasedIn2013*.bookName
assert "Angels And Demons" in booksReleasedBefore2013*.bookName
If you do not have such(blogs case) case, then I would use the example cited above for both optimization and performance . 如果您没有这种情况(博客情况),那么我将使用上面引用的示例进行优化和性能改进 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.