如何告诉 spring jpa 存储库中的 @query 不要使用准备好的语句(导致查询非常慢)?
How to tell my @query in spring jpa repository NOT to use prepared statement (lead to very slow queries)?
在我的 Spring 存储库 Class 中,我在 Postgresql 9.6 服务器上有以下查询(一种分析查询)运行 :
@Query("SELECT d.id as departement_id, COUNT(m.id) as nbMateriel FROM Departement d LEFT JOIN d.sites s LEFT JOIN s.materiels m WHERE "
+ "(s.metier.id IN (:metier_id) OR :metier_id IS NULL) AND (s.entite.id IN (:entite_id) OR :entite_id IS NULL) "
+ "AND (m.materielType.id IN (:materielType_id) OR :materielType_id IS NULL) AND "
+ "(d.id= :departement_id OR :departement_id IS NULL) "
+ "AND m.dateLivraison is not null and (EXTRACT(YEAR FROM m.dateLivraison) < :date_id OR :date_id IS NULL) "
+ "AND ( m.estHISM =:estHISM OR :estHISM IS NULL OR m.estHISM IS NULL) "
+ "GROUP BY d.id")
List<Map<Long, Long>> countByDepartementWithFilter(@Param("metier_id") List<Long> metier_id,@Param("entite_id") List<Long> entite_id,@Param("materielType_id") List<Long> materielType_id,
@Param("departement_id") Long departement_id, @Param("date_id") Integer date_id,
@Param("estHISM") Boolean estHISM);
问题是:使用不同的参数组合多次调用此查询,调用 5-6 次后,执行时间从 从 20 毫秒变为 10000 毫秒
据我所知,这是因为 prepared statements 的使用不适合分析查询,其中有许多参数的值可以改变很多。事实上,运行 上面的直接查询总是很快的(20 毫秒)。
问题 1:我如何告诉 Spring JPA 不要对这个特定查询使用准备好的语句?
问题 2:如果问题 1 无法解决,我有什么解决方法?
一般来说,有一些技巧可以提高 JPA/DB POV 的查询性能:
1- 使用@NamedQuery 而不是@Query
2- 对于报告查询,不要 运行 它在事务中
3- 如果不需要在查询前刷新持久化上下文,可以将刷新模式设置为COMMIT 运行s
4- 检查生成的查询,在 SQL developer od TOAD 上获取它并 运行 它,检查它的成本和 运行 策略,如果你也可以咨询你的 DBA可以使用一些本机 DB 函数/过程来增强它,因此使用本机查询而不是 JPQL 查询
5-如果返回的数据量很大,可以考虑把这个查询做成DB视图或者物化视图直接调用
6-例如利用查询提示来激活某个索引,注意在JPQL的情况下索引可能会被忽略
7- 如果查询提示在 JPQL 上不起作用,您可以使用本机查询
8- 在将 SQL 开发人员上的查询与代码中的查询进行比较时,请确保您比较正确,查询可能 运行 最初直接在 DB 上非常快,但需要很长时间才能完成获取所有数据,您可能会将这个初始的短时间与应用程序数据获取时间进行比较
9- 根据您的提供商使用提取大小提示
10- 据我所知,如果您使用本机非参数化查询(因此使用手动占位符并手动替换值),您可能会逃避准备好的语句,但通常应谨慎使用并尽可能避免,因为SQL 注入漏洞,也不允许数据库查询引擎以及休眠引擎预编译查询
在我的 Spring 存储库 Class 中,我在 Postgresql 9.6 服务器上有以下查询(一种分析查询)运行 :
@Query("SELECT d.id as departement_id, COUNT(m.id) as nbMateriel FROM Departement d LEFT JOIN d.sites s LEFT JOIN s.materiels m WHERE "
+ "(s.metier.id IN (:metier_id) OR :metier_id IS NULL) AND (s.entite.id IN (:entite_id) OR :entite_id IS NULL) "
+ "AND (m.materielType.id IN (:materielType_id) OR :materielType_id IS NULL) AND "
+ "(d.id= :departement_id OR :departement_id IS NULL) "
+ "AND m.dateLivraison is not null and (EXTRACT(YEAR FROM m.dateLivraison) < :date_id OR :date_id IS NULL) "
+ "AND ( m.estHISM =:estHISM OR :estHISM IS NULL OR m.estHISM IS NULL) "
+ "GROUP BY d.id")
List<Map<Long, Long>> countByDepartementWithFilter(@Param("metier_id") List<Long> metier_id,@Param("entite_id") List<Long> entite_id,@Param("materielType_id") List<Long> materielType_id,
@Param("departement_id") Long departement_id, @Param("date_id") Integer date_id,
@Param("estHISM") Boolean estHISM);
问题是:使用不同的参数组合多次调用此查询,调用 5-6 次后,执行时间从 从 20 毫秒变为 10000 毫秒
据我所知,这是因为 prepared statements 的使用不适合分析查询,其中有许多参数的值可以改变很多。事实上,运行 上面的直接查询总是很快的(20 毫秒)。
问题 1:我如何告诉 Spring JPA 不要对这个特定查询使用准备好的语句?
问题 2:如果问题 1 无法解决,我有什么解决方法?
一般来说,有一些技巧可以提高 JPA/DB POV 的查询性能:
1- 使用@NamedQuery 而不是@Query
2- 对于报告查询,不要 运行 它在事务中
3- 如果不需要在查询前刷新持久化上下文,可以将刷新模式设置为COMMIT 运行s
4- 检查生成的查询,在 SQL developer od TOAD 上获取它并 运行 它,检查它的成本和 运行 策略,如果你也可以咨询你的 DBA可以使用一些本机 DB 函数/过程来增强它,因此使用本机查询而不是 JPQL 查询
5-如果返回的数据量很大,可以考虑把这个查询做成DB视图或者物化视图直接调用
6-例如利用查询提示来激活某个索引,注意在JPQL的情况下索引可能会被忽略
7- 如果查询提示在 JPQL 上不起作用,您可以使用本机查询
8- 在将 SQL 开发人员上的查询与代码中的查询进行比较时,请确保您比较正确,查询可能 运行 最初直接在 DB 上非常快,但需要很长时间才能完成获取所有数据,您可能会将这个初始的短时间与应用程序数据获取时间进行比较
9- 根据您的提供商使用提取大小提示
10- 据我所知,如果您使用本机非参数化查询(因此使用手动占位符并手动替换值),您可能会逃避准备好的语句,但通常应谨慎使用并尽可能避免,因为SQL 注入漏洞,也不允许数据库查询引擎以及休眠引擎预编译查询