Database 性能休眠@Subselect vs数据库视图

Database 性能休眠@Subselect vs数据库视图,database,spring-boot,performance,hibernate,view,Database,Spring Boot,Performance,Hibernate,View,我有一个基于Java8SpringBoot2.3.3的应用程序(使用Hibernate5.4.20),我有一个Postgresql。 我想最终了解(为了性能)使用或不使用数据库视图和/或@Subselect是否更好 简单概述一下:我有一个实体“Book”和3个实体“BookRank”(用户给书籍加1到10颗星),“BookComment”(用户对书籍的评论),“BookLike”(用户对书籍的评论),每个实体都有书籍关系(manytone),因此在我的查询结果中,我希望以这种方式订购书籍: or

我有一个基于Java8SpringBoot2.3.3的应用程序(使用Hibernate5.4.20),我有一个Postgresql。 我想最终了解(为了性能)使用或不使用数据库视图和/或@Subselect是否更好

简单概述一下:我有一个实体“Book”和3个实体“BookRank”(用户给书籍加1到10颗星),“BookComment”(用户对书籍的评论),“BookLike”(用户对书籍的评论),每个实体都有书籍关系(manytone),因此在我的查询结果中,我希望以这种方式订购书籍:

order by avg(book_rank) desc, sum(book_rank) desc, count(book_comment) desc, count(book_like) desc
当然有很多书,很多排名,评论和喜欢…:)

从一个复杂的查询开始,我找到了4种方法来做同样的事情,里面有3个子选择(这对我来说是最好的解决方案,但是如果有人有更好的方法,请告诉我)

我想知道哪一个是最好的

1)存储库中的纯本机查询-无视图-无不可变实体

在我的存储库中,我有一个上面写的本地查询的方法

2)在存储库中具有数据库视图和本机查询

使用查询的中心部分创建数据库视图:

create or replace view book_ranking as

    select bbb.id as book_id, min(bbb.b_rank_average) as b_rank_average, min(bbb.b_rank_sum) as b_rank_sum, min(bbb.b_comment_count) as b_comment_count, count(b_l.id) as b_like_count
    from(
        select rr.id, min(bb.b_rank_average) as b_rank_average, min(bb.b_rank_sum) as b_rank_sum, count(b_c.id) as b_comment_count
        from(           
            select b.id,  avg(b_r.rank) as b_rank_average, sum(b_r.rank) as b_rank_sum
            from book as b
            left join book_rank as b_r on (b.id = b_r.book_id and b_r.deleted = false)
            group by b.id) as bb
            
        left join book_comment as b_c on (bb.id = b_c.book_id and b_c.deleted = false)
        group by bb.id) as bbb
                
    left join book_like as b_l on (bbb.id = b_l.book_id and b_l.deleted = false)
    group by bbb.id
并在repository方法中修改本机查询以仅使用视图:

select * 
from book_ranking as the_view
left join book on the_view.book_id = book.id 
where book.deleted = false
order by b_rank_average desc nulls last, b_rank_sum desc nulls last, b_comment_count desc, b_like_count desc, book_id desc;
3)使用数据库视图和选择存储库中的视图和jpql查询的不可变实体

使用实体(不可变)封装上述视图

@Entity
@Subselect("select * from book_ranking")
public class BookRanking implements Serializable {
    ....
}
以及修改连接Book实体和新BookRanking不可变实体(即视图)的存储库查询(非本机)

4)没有视图,但具有@subselect中的查询和存储库中的jpql查询的不可变实体

数据库上没有视图,但不可变实体BookRanking在@Subselect注释中有查询,带有“查看查询”和@Synchronize注释,如下所示:

@Entity
@Subselect("select bbb.id as book_id, min(bbb.b_rank_average) as b_rank_average, min(bbb.b_rank_sum) as b_rank_sum, min(bbb.b_comment_count) as b_comment_count, count(b_l.id) as b_like_count
    from(
        select rr.id, min(bb.b_rank_average) as b_rank_average, min(bb.b_rank_sum) as b_rank_sum, count(b_c.id) as b_comment_count
        from(           
            select b.id,  avg(b_r.rank) as b_rank_average, sum(b_r.rank) as b_rank_sum
            from book as b
            left join book_rank as b_r on (b.id = b_r.book_id and b_r.deleted = false)
            group by b.id) as bb
            
        left join book_comment as b_c on (bb.id = b_c.book_id and b_c.deleted = false)
        group by bb.id) as bbb
                
    left join book_like as b_l on (bbb.id = b_l.book_id and b_l.deleted = false)
    group by bbb.id )

@Synchronize({ "book", "book_rank", "book_comment", "book_like" })

public class BookRanking implements Serializable {
    ....
}


通常,使用相同的存储库查询(非本机)将Book实体和第3点的新BookRanking不可变实体(类似于视图)连接起来,数据库视图只是一个关系,通常在解析期间扩展为查询计划,因此,在使用视图和直接写出整个查询时,应该没有明显的区别。使用视图可以更容易地重用查询,但是当您想要更改某些内容时,您必须更改视图,可能还必须更改使用该视图的所有应用程序,因此可重用性方面可能会对您造成不利影响

我通常不推荐视图,因为我看到人们在视图中加入了很多不必要的连接,其唯一目的是“让其他人更容易”。不使用连接的问题是,数据库通常无法消除它们。TLDR,我建议直接在代码中写出查询,因为可以省略不需要的连接,从而获得更好的性能

您可以使用以下更简单的查询:

select 
    b.id, 
    avg(b_r.rank) as b_rank_average, 
    sum(b_r.rank) as b_rank_sum,
    (select count(*) from book_comment as b_c where b.id = b_c.book_id and b_c.deleted = false) as b_comment_count
    (select count(*) from book_like as b_l where b.id = b_l.book_id and b_l.deleted = false) as b_like_count
from book as b
left join book_rank as b_r      on (b.id = b_r.book_id and b_r.deleted = false)
where b.deleted = false
group by b.id
order by b_rank_average desc nulls last, b_rank_sum desc nulls last, b_comment_count desc, b_like_count desc, b.id desc
也可以使用JPQL/HQL查询对其进行建模。看起来非常相似:

select 
    b.id, 
    avg(r.rank) as b_rank_average, 
    sum(r.rank) as b_rank_sum,
    (select count(*) from b.comments c where c.deleted = false) as b_comment_count
    (select count(*) from b.booksLike l where l.deleted = false) as b_like_count
from book as b
left join b.ranks as r on r.deleted = false
where b.deleted = false
group by b.id
order by b_rank_average desc nulls last, b_rank_sum desc nulls last, b_comment_count desc, b_like_count desc, b.id desc
select 
    b.id, 
    avg(b_r.rank) as b_rank_average, 
    sum(b_r.rank) as b_rank_sum,
    (select count(*) from book_comment as b_c where b.id = b_c.book_id and b_c.deleted = false) as b_comment_count
    (select count(*) from book_like as b_l where b.id = b_l.book_id and b_l.deleted = false) as b_like_count
from book as b
left join book_rank as b_r      on (b.id = b_r.book_id and b_r.deleted = false)
where b.deleted = false
group by b.id
order by b_rank_average desc nulls last, b_rank_sum desc nulls last, b_comment_count desc, b_like_count desc, b.id desc
select 
    b.id, 
    avg(r.rank) as b_rank_average, 
    sum(r.rank) as b_rank_sum,
    (select count(*) from b.comments c where c.deleted = false) as b_comment_count
    (select count(*) from b.booksLike l where l.deleted = false) as b_like_count
from book as b
left join b.ranks as r on r.deleted = false
where b.deleted = false
group by b.id
order by b_rank_average desc nulls last, b_rank_sum desc nulls last, b_comment_count desc, b_like_count desc, b.id desc