Java 优化Spring数据JPA查询

Java 优化Spring数据JPA查询,java,spring-data-jpa,Java,Spring Data Jpa,我正在为框架生成的查询寻找可能的优化。 据我了解,过程如下: 您可以将域对象声明为POJO,并添加一些注释,如@Entity、@Table、@ManyToOne等 您可以声明您的存储库,例如每个接口 对于(2),您有几个选项来描述您的查询:例如,每方法名或@query 如果我编写如下查询: @Query("select t from Order t LEFT join fetch t.orderPositions where t.id = ?1") Page<Order> fin

我正在为框架生成的查询寻找可能的优化。 据我了解,过程如下:

  • 您可以将域对象声明为POJO,并添加一些注释,如
    @Entity
    @Table
    @ManyToOne

  • 您可以声明您的存储库,例如每个接口

对于(2),您有几个选项来描述您的查询:例如,每方法名或
@query

如果我编写如下查询:

@Query("select t from Order t LEFT join fetch t.orderPositions where t.id = ?1")
Page<Order> findById(Pageable pageable, String id);
所以,如果我需要来自多个连接对象的一些信息,那么一个查询可能会非常昂贵:而且更有趣的是,它会非常低效。我偶然发现了一个缓慢的查询,MySQL解释告诉我,在生成的查询中,优化器无法使用索引,这很糟糕

当然(我知道)我必须权衡,生成的SQL并不像手工编写的SQL那么理想,而且具有编写较少样板代码的优势

我的问题是:改进查询、查询执行的好策略是什么

我自己想了一些选择:

1) 是否可以为不同的目的定义多个“实体”,例如访问订单的完整特征的
订单
,以及具有较少列且不解析
联接列
过滤器过滤器
?两者都将引用相同的表,但其中一个将使用所有列,而另一个仅使用部分列

2) 使用
@Query(…native=“true”)
选择我要使用的所有列。这样做的好处是,我不会将我的域对象翻一番,也不会用成百上千的
过滤的
-对象乱扔我的代码库。
传呼呢?将
pageable
@Query(…native=“true”)
结合使用仍然可行(恐怕不行)

3) 最后,但在我看来是“最差的”/样板解决方案:使用
jdbcmetemplates
并在较低的级别上做一些事情

还有其他我没有想到的选择吗? 感谢您对该主题的任何启发:]

更新: 我们目前的战略如下

1) 在可能的情况下,我使用select new 正如我所说,这适用于每个对象(无论是实体还是POJO)

2) 结合数据库视图,可以充分利用SQL和ORM。对于某些用例,手头有一个聚合的结果集可能是有意义的。将此resultset定义为一个视图,可以从db角度轻松地使用简单的select语句查看结果。
对于ORM方面,这意味着您可以轻松定义一个与此视图匹配的实体,并将整个ORM的优点放在最上面:包括分页在内的一个解决方案是使用DTO:

@Query("select new FilteredOrder(o.name, o.size, o.cost) from Order o where o.id = ?1")
Page<FilteredOrder> findFilteredOrderById(Pageable pageable, String id);
@Query(“从订单o中选择新的筛选器(o.name、o.size、o.cost),其中o.id=?1”)
PageFindFilteredOrderById(可分页,可分页,字符串id);

如果您想使用实体生成某些报告,也许应该考虑使用nosql数据存储?

看看JPA的延迟抓取策略。它允许您选择没有关系的对象,但在引用它们时会获取关系。

首先,我会忘记优化列读取,因为(除非您有数百列的表),任何性能增益都可能是最小的:请参阅19.1.7。这就简化了您的模型,因为您只需要处理优化关联/加入。非常感谢您的链接!我来看看:]主要问题可能是临时不需要的实体的连接。是的,这无疑是我们在使用ORM工具时面临的最大问题。你的问题没有明确的答案。我会避免重复实体。更好的策略是在回购协议中编写不同的方法,例如findById和FindByIdWithXYZ。当屏幕或报表需要数据时,另一种策略是定义一个数据库视图,并将某个只读实体映射到该视图(工作方式与表类似)。Hibernate Fetch概要文件在上一个链接(假设您使用的是Hibernate)的20.1.7中很有用,但不知道将这些文件与Spring Data.Hm集成的最佳方法。我担心,确实没有真正的答案,或者没有一个简单的答案。我认为我们的项目正面临着ORM的一些限制。就像其他一切一样。做一件最简单的事情,那就是让所有的事情都变得懒惰,并在分析之后进行优化。对于那些查询效率极低的情况,您可以通过连接、获取配置文件、db视图、DTO等或任何最适合当前用例的方式进行优化。问题是,对于某些请求,我需要解决3-4个连接,但有时仅针对一列或两列。我尽可能多地使用延迟抓取。正如@AlanHay指出的,除非您的表有数百列,或者一次检索数百行,否则限制所选列的数量可能是过早的优化。实际上,您可能不需要担心它,编写代码来处理它只会让您有一个更复杂的系统需要维护。也许效果比我预期的要小。最让我困惑的是:我有一个超过180k条目的简单查询。简单任务,简单SQL。手动操作(连接相同的表,选择较少的列)不仅速度更快(1s 3s),而且生成的SQL效率非常低,因为MySQL无法使用(右侧)索引。在这一点上,我唯一的解释是——连接是相同的——不同的列很重要。那只是几张小桌子。我必须处理数百万行,其中速度损失远远高于2s。是的,对于您的用例,我认为手写SQL可能是最好的。根据我的经验,O/R映射器的最佳工作点是处理单个“根”域对象(或几个),以及它的相关层次结构。在…上
@Query("select new FilteredOrder(o.name, o.size, o.cost) from Order o where o.id = ?1")
Page<FilteredOrder> findFilteredOrderById(Pageable pageable, String id);