[英]How to Execute multiple JPA queries in a single JDBC Connection
In a Spring-boot application, I am using JPA with Hibernate.在 Spring-boot 应用程序中,我使用 JPA 和 Hibernate。
I have a custom select query method with parameterised IN Clause defined in JPA Repository.我有一个自定义 select 查询方法,在 JPA 存储库中定义了参数化的 IN 子句。 Since the the data is huge, I am executing multiple times the same query with small batches of ID passed as parameters.由于数据量很大,我正在执行多次相同的查询,并将小批量的 ID 作为参数传递。 But I am not able to Improve the performance.但我无法提高性能。
There are around 200000 records and the Time taken is 1 min.大约有 200000 条记录,所用时间为 1 分钟。 Which is very Huge.这是非常巨大的。
Following are the things that i tired以下是我累的事情
When i analysed the Hibernate statics: the following are the logs found:当我分析 Hibernate 静态数据时:以下是找到的日志:
( 382016470 nanoseconds spent acquiring 1 JDBC connections; 0 nanoseconds spent releasing 0 JDBC connections; 798909958 nanoseconds spent preparing 1 JDBC statements; 305523944 nanoseconds spent executing 1 JDBC statements; 0 nanoseconds spent executing 0 JDBC batches; 0 nanoseconds spent performing 0 L2C puts; 0 nanoseconds spent performing 0 L2C hits; 0 nanoseconds spent performing 0 L2C misses; 0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections); 0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections) ( 382016470 nanoseconds spent acquiring 1 JDBC connections; 0 nanoseconds spent releasing 0 JDBC connections; 798909958 nanoseconds spent preparing 1 JDBC statements; 305523944 nanoseconds spent executing 1 JDBC statements; 0 nanoseconds spent executing 0 JDBC batches; 0 nanoseconds spent performing 0 L2C puts; 0执行 0 个 L2C 命中所花费的纳秒;执行 0 个 L2C 未命中所花费的 0 纳秒;执行 0 个刷新所花费的 0 纳秒(总共刷新 0 个实体和 0 个集合);执行 0 个部分刷新所花费的 0 纳秒(总共刷新 0 个实体和 0 个集合)
It takes time to create JDBC Connection even with Hikari connection Pool.即使使用 Hikari 连接池,创建 JDBC 连接也需要时间。 Following are the hikari properties以下是光属性
spring.datasource.hikari.connection-timeout=120000
spring.datasource.hikari.maximum-pool-size=100
spring.datasource.hikari.minimum-idle=30
spring.jpa.hibernate.connection.provider_class=org.hibernate.hikaricp.internal.HikariCPConnectionProvider
spring.datasource.hikari.pool-name=HikariConnectionPool
spring.datasource.hikari.data-source-properties.cachePrepStmts=true
spring.datasource.hikari.data-source-properties.useServerPrepStmts=true
And For each jpa query JDBC connection is established, prepared.并且对于每个 jpa 查询 JDBC 连接建立,准备。 Even after setting the following properties即使设置了以下属性
spring.datasource.hikari.data-source-properties.cachePrepStmts=true spring.datasource.hikari.data-source-properties.useServerPrepStmts=true spring.datasource.hikari.data-source-properties.cachePrepStmts=true spring.datasource.hikari.data-source-properties.useServerPrepStmts=true
I have kept the number of parameters for IN Clause constant我保持 IN 子句的参数数量不变
Code Snippnet代码片段网
//JPA Reposistry
public interface CarRepository extends CrudRepository<Car, String>, JpaSpecificationExecutor<Car> {
@Query(SELECT u.carName as carName,
u.carId as
carId from
Car u
where u.carId in (:carIds))
List<CarP> findCarProjections@Param("carIds")Set<String> carIds);
}
//Service
@Component public carService
{
@Autowired
CarRepository carRepo;
public void processCars(List<carId> carIds)
{
List<List<String>> carIdPartioned = partionCarIds(carIds)
ExecutorService es = Executors.newFixedThreadPool(10);
for(List<String> carIdPart : carIdPartioned)
es.submit(new ProcessCarInThread(carIdPart,carRepo));
}
//Each Call Creates a new connection to JDBC
//Takes time to prepare Statement ( as given in hibernate statics )
class ProcessCarInThread implements Runnable
{
List<String> carIds;
CarRepository carRepo;
public ProcessCarInThread(List<String> carIds, CarRepository carRepo )
{
this.carIds=carIds;
this.carRepo=carRepo;
}
@Override
public void run() {
//query 1
List<CarP> cars=carRepo.findCarProjections(carIds);
//query 2
List<SomeotherEntity> cars=otherRepo.findSomethingElse(params);
//even query 1 and query2 is not executing in a single JDBC connection
//Do Something
}
}
I want to improve the performance, any suggestions are welcome.我想提高性能,欢迎提出任何建议。
Any way to avoid JDBC query preparation time or JDBC connection acquiring time?有什么方法可以避免 JDBC 查询准备时间或 JDBC 连接获取时间?
Very surprisingly, a similar performance issue was faced in my current application post PROD deployment.非常令人惊讶的是,在我当前的应用程序后 PROD 部署中也遇到了类似的性能问题。 And fortunately we were able to fix it.幸运的是,我们能够修复它。
Root cause : we observed that using multiple input parameter in @Query is causing performance issue.根本原因:我们观察到在@Query 中使用多个输入参数会导致性能问题。
@Query(SELECT u.carName as carName, u.carId as carId from Car u where u.carId in (:carIds))
Solution : Use entityManager
instead to form similar query dynamically and significant improvement is performance was observed解决方案:使用entityManager
代替动态形成类似的查询,并显着提高性能是观察到的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.