Как я могу улучшить производительность медленного метода JpaRepository с очень быстрым запросом (запускается на PL / SQL разработчику)? - PullRequest
0 голосов
/ 29 августа 2018

У меня был репо (извините за португальские слова):

public interface EntityARepository extends JpaRepository<EntityA, Long> {

  @Query("select new package.someDTO(lan.dataLancamento, lan.prazoVinculado, lan.valor, his.tipo, his.descricao) "
      + "from EntityA lan, EntityB his, EntityC cc "
      + "where lan.conta = cc.idCc "
      + "and   lan.historico = his.idHistorico "
      + "and   lan.dataLancamento >= :presente "
      + "and   lan.dataLancamento <= :futuro "
      + "and   cc.agencia = :agencia "
      + "and   cc.numConta = :conta "
      + "order by lan.dataLancamento asc")
  public List<someDTO> findByAgenciaAndContaEntreDatas(@Param("agencia") Long agencia, @Param("conta") Long conta, @Param("presente") Date presente, @Param("futuro") Date futuro);

И этот метод работает, но для возврата списка из 3 элементов требуется 5-6 секунд. В PL / SQL Developer этот же запрос занимает 0,015 с:

select lan.data_lancamento,
       lan.prazo_vinculacao,
       lan.valor,
       his.tipo_lancamento,
       his.descricao
  from tableA lan, tableB his, tableC cc
 where lan.cc = cc.id_cc
   and lan.historico = his.id_historico
   and lan.data_lancamento >= '17/05/2012'
   and lan.data_lancamento <= '17/08/2012'
   and cc.agencia = 1
   and cc.num_conta = 201243
 order by lan.data_lancamento asc;

Я использую локальную базу данных Oracle. Как я могу улучшить этот запрос, чтобы быть быстрее? Я думал, что мог бы использовать nativeQuery = true, но это остановит использование new package.someDTO, и поскольку мой запрос смешивает данные из 2 таблиц и использует 3-ю для проверки некоторых данных. Я не могу создать новый репозиторий на основе моего DTO, поскольку у него нет первичного ключа и уникального атрибута.

1 Ответ

0 голосов
/ 29 августа 2018

Эти два запроса похожи, но они очень разные. Каждое различие может быть источником вашей проблемы с производительностью.

  1. первый - запрос JPQL, а второй - SQL. Это означает, что

    а. Он должен быть преобразован в SQL, который может выглядеть совсем по-другому. Используйте функцию ведения журнала вашей реализации JPA, чтобы дважды проверить, какие операторы действительно выполняются. б. Он не только возвращает некоторые необработанные данные, но и создает экземпляры Java-объектов. В зависимости от того, как выглядит ваш конструктор, это может занять значительное время.

  2. первый использует переменные связывания, а второй использует литералы. Oracle достаточно умен, чтобы посмотреть на фактическое предложение where, чтобы оценить, сколько строк он отфильтровывает. Но он не может этого сделать, если он имеет только переменные связывания. Поэтому у вас могут быть совершенно другие планы объяснения. => После того, как вы зарегистрировали фактически выполненный оператор, получите план объяснения для этого оператора (включая переменные связывания) и сравните его с тем, который работает хорошо. Это может дать вам подсказку для дополнительных индексов или аналогичных, которые могут помочь. Если вам нужна дополнительная помощь, попробуйте дополнить вопрос двумя планами объяснения.

  3. Метод java возвращает все результаты, которые он получает из базы данных, в то время как большинство инструментов SQL просто получают первые строки. Это также может быть важным отличием. Перед тем, как остановить просмотр, убедитесь, что во время просмотра SQL все строки отображаются.

...