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

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

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

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

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

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

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

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

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

都开延迟 按需返回字段

JOIN 了 9 張表, 不能算簡單查詢吧.你可以試試手寫 SQL, 9 表 JOIN , 看能提升多少.

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

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

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

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

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

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

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

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

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

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

嗯,值得试一下

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

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

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

#4 简单试试加个
只能提取业务结果,将 SQL 尽可能压缩,取按需内容。

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

我来试试 i

我技术水平不够,还是喜欢用 mybatis ,这样自己好把控细节建议 @ 一下 v2 上常常出来 diss mybatis 的 hibernate 大神来帮你优化

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

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

/ 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 www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License v. 1.0 which is available at 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.0package javax.persistence;/ Defines strategies for fetching data from the database. The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY 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 LAZY strategy hint has been specified.

  Example:  &#064;Basic(fetch=LAZY)  protected String getName() { return name; }  
Basic ElementCollection ManyToMany OneToMany ManyToOne OneToOne 1.0 /public enum FetchType { / Defines that data can be lazily fetched. / LAZY, / Defines that data must be eagerly fetched. / EAGER}不看文档,不查手册的吐槽我不是很认可

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

projection query

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

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

晒代码,别虚空打靶

了解一下,EntityGraph

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

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

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

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

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

#41 上原文链接

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

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

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

好的,感谢

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

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

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

#45 这本书是付费书籍,你这又连完整原文截图都没有,你这是在自认「断章取义」,还是在自认「没看原文而是看了某人的断章取义」。这个图应该是真的,但是它需要结合完整原文才能知道说得是什么。这里比较的很可能是,「直接用 Hibernate 的 API 」、「用 JDK 的 JPA 」 、用「 Spring Data JPA 」 ,这三种,使用 Hibernate 的途径的性能。 三个都是 Hibernate ,只不过使用方式不同。

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

不能抱有敌意,根据对技术喜好看问题。如果你换成 mybatis 也会面临其他的问题,也没有办法保证百分百没有其他的问题。在有限的空间内做最大程度的优化就好,即使就是搞不定了,需要重构,也是需要多人讨论,评审后,再下结论,做选型,做改造。说句不好听的话,接手了屎山,改造就好比屎山雕花,有时候盲目的重构,弄完发现不过是在屎山旁边又拉了一坨。

嗯,确实烂的一塌糊涂

没错,这种工作吃力不讨好的,没有一种方案是能够保证百分百解决的。

Hibernate 的初衷就是想偷懒,想回避关系数据库,结果到了最后,发现在 Hibernate 体系里面学那么多、写那么多,依旧耗费大量精力,而且还不如一条手写 SQL 搞定。

给 OP 提供一个解决方案,比如有个文章表,和一个 User 表,我要查询所有文章列表,文章列表又要返回这篇文章的作者信息,我这里写了一个投影和一个 DTO ,用 nativeQuery 方式查询。public class UserInfoDto { private Long id; private String name; private String avatar;}public interface PostInfo { long getCreateTime(); long getModifiedTime(); Long getId(); String getTitle(); String getSummary(); String getContent(); ("#{new com.momo.xxx.dto.UserInfoDto(target.user_id, target.user_name, target.user_avatar)}") UserInfoDto getAuthor();}user_info 表示用户表,Post 表示文章列表。(value = "SELECT p.id,user_info.id AS user_id, user_info.name AS user_name, user_info.avatar AS user_avatar,p.title,p.summary,p.CONTENT,p.state,p.create_time AS createTime,p.modified_time AS modifiedTime FROM Post p JOIN user_info ON user_info.id=p.author_id WHERE p.is_delete = FALSE AND p.STATE = 5 ORDER BY p.ID DESC", nativeQuery = true) Page findAllPublishedPostsNative(Pageable pageable);如果直接用 Spring Data Jpa 查询 10 条数据大概要 4192ms ,可能更慢,用 Native 方式可能只要 130ms ,这个数据只是我的一个测试数据;

你应该这么想想,Hibernate 要是如你所说的那么拉,它还能在国外称霸那么多年吗?