Как выполнить несколько запросов JPA в одном соединении JDBC - PullRequest
1 голос
/ 24 октября 2019

В приложении Spring-boot я использую JPA с Hibernate.

У меня есть собственный метод запроса select с параметризованным предложением IN, определенным в репозитории JPA. Поскольку данные огромны, я выполняю несколько раз один и тот же запрос с небольшими пакетами идентификаторов, передаваемых в качестве параметров. Но я не могу улучшить производительность.

Есть около 200000 записей, а время заняло 1 минуту. Который очень Огромный.

Ниже приведены вещи, которые мне надоели

  1. Выбор только нужных столбцов вместо всего POJO -> сократил время запроса на 8 секунд
  2. При анализе статики Hibernate: были найдены следующие журналы:

    (382016470 наносекунд потрачено на получение 1 соединения JDBC; 0 наносекунд потрачено на освобождение 0 соединений JDBC; 798909958 наносекунд потрачено на подготовку 1 оператора JDBC; 305523944 потрачено наносекунды;выполнение 1 операторов JDBC; 0 наносекунд, потраченных на выполнение 0 пакетов JDBC; 0 наносекунд, потраченных на выполнение 0 операций L2C; 0 наносекунд, потраченных на выполнение 0 попаданий L2C; 0 наносекунд, потраченных на выполнение 0 промахов L2C; 0 наносекунд, потраченных на выполнение 0 сбросов (сброс всего 0 объектов)и 0 коллекций); 0 наносекунд, потраченных на выполнение 0 частичных сбросов (сброс всего 0 сущностей и 0 коллекций)

Создание соединения JDBC требует времени даже при использовании пула соединений Hikari. Хикарисвойства

 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

А Для каждого запроса jpa установлено соединение JDBC, подготовлено. Даже после установки следующих свойств

spring.datasource.hikari.data-source-properties.cachePrepStmts = true spring.datasource.hikari.data-source-properties.useServerPrepStmts = true

Я сохранил число параметров для предложения IN константным

Фрагмент кода

//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
}

}

Я хочу улучшить производительность, любые предложения приветствуются.

Любой способ избежать времени подготовки запроса JDBC или времени получения соединения JDBC?

1 Ответ

1 голос
/ 25 октября 2019

Очень удивительно, что с аналогичной проблемой производительности столкнулся в моем текущем приложении после развертывания PROD. К счастью, мы смогли это исправить.

Основная причина : мы заметили, что использование нескольких входных параметров в @Query вызывает проблемы с производительностью.

@Query(SELECT u.carName as carName, u.carId as carId from Car u where u.carId in (:carIds))

Решение : вместо этого используйте entityManager для динамического формирования аналогичного запроса, и наблюдается значительное улучшение производительности

...