【发布时间】:2020-09-21 12:13:47
【问题描述】:
我有一个基于 Java 8 Spring Boot 2.3.3 的应用程序(使用 hibernate 5.4.20),我有一个 Postgresql。 我想最终了解使用或不使用数据库视图和或@Subselect 是否更好(对于性能)。
只是快速概述:我有一个实体“Book”和 3 个实体“BookRank”(用户给书籍 1 到 10 个 星),“BookComment”(用户对书籍的评价) ,“BookLike”(用户将 like 放在书籍中)每个都具有书籍关系(ManyToOne),所以在我的查询结果中,我想以这种方式订购书籍:
order by avg(book_rank) desc, sum(book_rank) desc, count(book_comment) desc, count(book_like) desc
当然有很多书,很多等级,cmets和点赞... :)
我发现了 4 种方法来做同样的事情,从一个复杂的查询开始,里面有 3 个子选择(这对我来说是最好的解决方案,但如果有人有更好的方法,请告诉我)。
select *
from(
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
) as bbbb
left join book on bbbb.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;
我想知道哪个性能最好...
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
并修改存储库方法中的本机查询只是为了使用视图:
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 不可变实体(即视图)的存储库查询(非原生)
@Query("select b from BookRanking as b_r
join Book b on b_r.bookId = b.id
where b.deleted = false
order by b_r.b_rank_average desc nulls last, b_r.b_rank_sum desc nulls last, b_r.b_comment_count desc, b_r.b_like_count desc, b_r.bookId desc)
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 不可变实体(类似于视图)的相同存储库查询(非本地)
【问题讨论】:
-
您使用了哪种策略,到目前为止结果如何?
标签: database spring-boot performance hibernate view