简体   繁体   English

休眠一对多关联:子选择或渴望

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM