5

Java Hibernate 复杂实体关联下,简单查询都很慢,如何优化?

 7 months ago
source link: https://www.v2ex.com/t/1013581
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  程序员

Java Hibernate 复杂实体关联下,简单查询都很慢,如何优化?

  XiaoJiang9527 · 6 小时 12 分钟前 · 1388 次点击

最近正在整改一个老项目,里面的表结构错综复杂,实体中的映射表字段基本都增加了 @ManyToOne 和 @JoinColumn 注解,导致很多简单单表查询都需要执行很久。 但是打印具体 hibernate SQL 日志,Explain 下,也不存在什么性能问题,各位大佬们,怎么解?

54 条回复    2024-02-02 15:55:02 +08:00
issakchill

issakchill      6 小时 9 分钟前

是不是查单表的时候 也自动遍历关联查了关联表的数据?
nothingistrue

nothingistrue      6 小时 7 分钟前

没 DDD 小聚合,或者类似的数据模型,不要用 Hibernate 。当然就算是用了 DDD ,也是用通过读写分离,来避开复杂查询的。
BiChengfei

BiChengfei      6 小时 7 分钟前

我不用 @ManyToOne 和 @JoinColumn ,都是在代码中手动关联查询,感觉这两个注解隐藏了太多细节。sql 都有了,就一个流程一个流程看呗,要么数据多,要么流程多
XiaoJiang9527

XiaoJiang9527      6 小时 4 分钟前

@issakchill 没错,一个简单查询能打印 6 条查询语句,有一个 SQL 甚至 JOIN 了 9 张表
XiaoJiang9527

XiaoJiang9527      6 小时 3 分钟前

@nothingistrue 看来复杂查询只能全部拆分成原生 SQL 去解决了。
XiaoJiang9527

XiaoJiang9527      6 小时 1 分钟前

@BiChengfei 流程一个一个看,给我震惊的不行,一个 hibernate 的 Query 方法,能打印 6 条查询语句 !!!
nothingistrue

nothingistrue      5 小时 59 分钟前

1 ,数据库弄个视图,然后单独给这个试图搞个纯查询的实体吧。2 ,如果 1 不可行,跑路。

这么多关联,你这是个屁的简单查询。
nothingistrue

nothingistrue      5 小时 57 分钟前

数据模型太烂,上谁都管不了。换成 SQL 也是复杂 SQL ,可能更慢。
yor1g

yor1g      5 小时 55 分钟前

@ManyToOne 都开延迟 按需返回字段
shyangs

shyangs      5 小时 55 分钟前

JOIN 了 9 張表, 不能算簡單查詢吧.

你可以試試手寫 SQL, 9 表 JOIN , 看能提升多少.
lybcyd

lybcyd      5 小时 55 分钟前

是不是 N+1 ,看看语句具体是怎么关联的
Sigrdirfa

Sigrdirfa      5 小时 54 分钟前

简单查询在我的概念里最狭义的是单表与其所对应的 Java 对象进行 crud 操作,稍微宽泛一点的是和一到两张有关联关系的表(关联表无其他与其关联表需要被查询)进行连表查询。

你这个对象是不是过于复杂了?
XiaoJiang9527

XiaoJiang9527      5 小时 53 分钟前

@nothingistrue 在 Hibernate 里面,我把 "service.queryData(conditionBean);" 称之为一个单表查询。
XiaoJiang9527

XiaoJiang9527      5 小时 52 分钟前

@nothingistrue 我也非常担心更改原生 SQL 后,更为糟糕。
XiaoJiang9527

XiaoJiang9527      5 小时 50 分钟前

@yor1g 实体之间的关系绑定,hibernate 好像没办法按需返回所需字段吧?
XiaoJiang9527

XiaoJiang9527      5 小时 49 分钟前

@lybcyd 打印出的 SQL ,用来分析,确实点问题没有,都是类似主外键查询,也是正常走的索引,就是极慢。一个接口能打印 30 个 SQL 。
XiaoJiang9527

XiaoJiang9527      5 小时 48 分钟前

@Sigrdirfa 数据模型太烂了,写的也烂。
XiaoJiang9527

XiaoJiang9527      5 小时 46 分钟前

@shyangs 还别说,手写 9 个表 join 查询 0.2 s ,跟 hibernate 输出的 SQL 基本一致。
Sanshi4396

Sanshi4396      5 小时 41 分钟前

直接在 Repo 里用 @Query 写原生 sql 语句,查询你想要的东西呗,不要用它的方法查询。
如果原生 sql 都很慢,那不能怪 hibernate 了。
Sanshi4396

Sanshi4396      5 小时 39 分钟前

还有你的查询是不是返回了 Page<>分页对象。这个对象返回的时候,是会多次查询的。
1 、查询你想要的单页数据 2 、查询数据总数
ZSeptember

ZSeptember      5 小时 36 分钟前

SQL 优化空间不大吧,主要是使用姿势。
什么复杂业务 ORM 用的这么花,互联网不是不让 join 吗
yor1g

yor1g      5 小时 36 分钟前

@XiaoJiang9527 可以按需的 开了延迟加载可以基本解决 n+1 问题 再优化的话要按需返回字段 + 基础表开 2 级缓存
XiaoJiang9527

XiaoJiang9527      5 小时 33 分钟前

@ZSeptember 互联网不让用,奈何 hibernate 机制在哪里,数据少和初期开发的时候压根不会考虑,后期优化头都大
XiaoJiang9527

XiaoJiang9527      5 小时 32 分钟前

@ZSeptember 只能提取业务结果,将 SQL 尽可能压缩,取按需内容。
XiaoJiang9527

XiaoJiang9527      5 小时 30 分钟前

@issakchill 最开始就是尝试过,改了之后一大堆空指针异常,改了 5 个后,放弃了这个方案。
Goooooos

Goooooos      5 小时 7 分钟前   ❤️ 1

我技术水平不够,还是喜欢用 mybatis ,这样自己好把控细节

建议 @ 一下 v2 上常常出来 diss mybatis 的 hibernate 大神来帮你优化
xuanbg

xuanbg      4 小时 59 分钟前

性能问题唯有手写 sql 可解。
UBcai

UBcai      4 小时 41 分钟前

勾起了我吐槽欲望。项目最开始架构要 Hibernate ,我说不行。我只要 a 表的 1,2,3 字段,hibernate 会查询全部字段,并且会查询 a 表的关联表 b 的字段,逻辑复杂后肯定有性能问题。架构说小公司,性能要不了那么高要求。说白了就是 hibernate 不用写 sql,当时他还没决定入职,怎么简单怎么来。老板还让我多和架构学学,不要还没学会走就想跑。后面果然不出我所料,出了各种大问题。你们敢想象 30 个人同时用,服务器直接崩了。
zhazi

zhazi      4 小时 22 分钟前

/*
* Copyright (c) 2008, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Linda DeMichiel - 2.1
// Linda DeMichiel - 2.0


package javax.persistence;

/**
* Defines strategies for fetching data from the database.
* The <code>EAGER</code> strategy is a requirement on the persistence
* provider runtime that data must be eagerly fetched. The
* <code>LAZY</code> strategy is a hint to the persistence provider
* runtime that data should be fetched lazily when it is
* first accessed. The implementation is permitted to eagerly
* fetch data for which the <code>LAZY</code> strategy hint has been
* specified.
*
* <pre>
* Example:
* @Basic(fetch=LAZY)
* protected String getName() { return name; }
* </pre>
*
* @see Basic
* @see ElementCollection
* @see ManyToMany
* @see OneToMany
* @see ManyToOne
* @see OneToOne
* @since 1.0
*/
public enum FetchType {

/** Defines that data can be lazily fetched. */
LAZY,

/** Defines that data must be eagerly fetched. */
EAGER
}

不看文档,不查手册的吐槽我不是很认可
XiaoJiang9527

XiaoJiang9527      4 小时 18 分钟前

@Goooooos 哈哈,又臭有长的代码,没有那个大佬看得下去叭
aragakiyuii

aragakiyuii      4 小时 17 分钟前 via Android

@UBcai projection query
XiaoJiang9527

XiaoJiang9527      4 小时 17 分钟前

@UBcai 目前我这个更是离谱,不过都是同一种类型的问题,先归结为机制问题吧
XiaoJiang9527

XiaoJiang9527      4 小时 13 分钟前   ❤️ 1

@zhazi 这个机制调整会导致我后续业务代码空指针,而且很多。 /狗头
zhazi

zhazi      2 小时 52 分钟前

@XiaoJiang9527 晒代码,别虚空打靶
Nosub

Nosub      2 小时 23 分钟前 via Android

了解一下,EntityGraph
Nosub

Nosub      2 小时 20 分钟前

@UBcai 投影 Projections 和 DTO 了解一下,如果遇到问题只会吐槽,肯定还是无法掌握 Hibernate 的。
Nosub

Nosub      2 小时 5 分钟前

还有个问题,很多人没有搞清楚 JPA ,Hibernate 和 Spring Data JPA 的关系,建议花点时间搞清楚这些概念,OP 说的是 Spring Data JPA 速度慢。
Nosub

Nosub      2 小时 0 分钟前

8bGI5JN.png
nothingistrue

nothingistrue      1 小时 47 分钟前

@Nosub #40 JPA 是标准,Hibernate 是一种实现 ,Spirng Data JPA 跟 Hibernate 就是 Spring Boot 跟 Spring 的关系。你这来源是瞎比较,你不能下。
dog82

dog82      1 小时 43 分钟前

实在不行就上物化视图,用空间换时间
Nosub

Nosub      1 小时 41 分钟前

@nothingistrue Hibernate 的开发团队写的,瞎在哪儿。
nothingistrue

nothingistrue      1 小时 40 分钟前

@Nosub #41 上原文链接
XiaoJiang9527

XiaoJiang9527      1 小时 35 分钟前

@dog82 准备重新提炼业务,切换实现方案,因为目前数据量不是很大,先用 SQL 开路解决
zhazi

zhazi      1 小时 29 分钟前

水平差,冤框架。让上代码也不上,block
Nosub

Nosub      1 小时 13 分钟前

@nothingistrue 你可以看看《 Java Persistence with Hibernate Second Edition 》,数据来自这本书,作者你也可以看看。
forbreak

forbreak      39 分钟前

说 hibernate 慢的,都是不愿意学高级用法。埋头狂写,能不慢吗。
wangYQ

wangYQ      35 分钟前

@XiaoJiang9527 但是这样的成本有点大,
1.老项目,其中业务饱经沧桑,如果有很熟悉业务的完全可以重新改,如果不存在业务完全了解的人,还是不要贸然干,不知道有什么特殊业务的坑藏在细小的地方。
2.SQL 单独执行很快,只是关联查询慢,看能不能把需要的数据通过数据库层面视图,冗余字段,减少一个接口调用太多的 SQL ,减少开销。
3.如果项目后期有更换数据库的需求,Hibernate ,JPA 这种还算是比较方便,换个方言能解决一大部分的事情,要是都是原生 SQL 用了一些特殊函数,改数据库的话工作量特别大
XiaoJiang9527

XiaoJiang9527      16 分钟前

@wangYQ 是的,目前真是没办法下手。
目前我对项目的选型和方案制定倒是没有很大的敌意,仅想寻找一种合适的解决方案。
上面大佬的那些方案目前正在一个个尝试。
nothingistrue

nothingistrue      6 分钟前

@Nosub #45 这本书是付费书籍,你这又连完整原文截图都没有,你这是在自认「断章取义」,还是在自认「没看原文而是看了某人的断章取义」。

这个图应该是真的,但是它需要结合完整原文才能知道说得是什么。这里比较的很可能是,「直接用 Hibernate 的 API 」、「用 JDK 的 JPA 」 、用「 Spring Data JPA 」 ,这三种,使用 Hibernate 的途径的性能。 三个都是 Hibernate ,只不过使用方式不同。
iyiluo

iyiluo      2 分钟前

屎山项目,除非整个模块重构,任何试图在旧代码上优化的行为都是往屎山上拉屎

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK