Как улучшить скорость выборочных запросов в Spring с Hibernate и PostgreSQL? - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть проект Spring Boot, который мне недавно удалось развернуть на VPS. Я был очень удивлен, когда запросы на выборку, которые почти мгновенно выполнялись на моей машине, замедлились до ползания там. Я знал, что это будет медленнее, я просто не ожидал так сильно.

Я создал тестовый проект, который воспроизводит проблему. Он выбирает около 20 000 строк из таблицы, которая содержит 100 000 строк. Создание запроса занимает около 100 мкс, а выполнение запроса - 0,5–2 с. Я попытался протестировать с 10 × больше строк, но это заняло намного больше времени, и в итоге выкинул OutOfMemoryError.

Я искал вокруг, и, похоже, это не должно занять много времени, тем более что мне кажется, что данных не так много. Я прочитал и узнал об индексах, но даже запрос, который должен быть хорошим примером использования индекса, занимает много времени. Выполнение запроса непосредственно в консоли psql занимает около 100 мс без индекса и 20 мс с.

Если вы хотите проверить его, загрузите сервер и клиент проекты и следуйте инструкциям там. Я начал с моего реального проекта и удалил как можно больше материала, но оставил его похожим, чтобы его можно было сравнить.


Мои спецификации VPS:

2 × 2,4 ГГц, процессор

2 ГБ ОЗУ

uname -a
Linux ampix 2.6.32-042stab127.2 #1 SMP Thu Jan 4 16:41:44 MSK 2018 x86_64 GNU/Linux

Debian Джесси

Java 8 x64

PostgreSQL 9.4

Spring Boot 2.0.1.RELEASE


Заранее спасибо.

Обновление 1 : забыл написать о тесте вне Spring и забыл, что я использовал 0,8 вместо 0,9 в критериях выбора, поэтому число выбранных строк больше, чем я написал первоначально.

Обновление 2 : использование производного запроса, возвращающего Stream<>, повышает производительность на незначительную величину.

1 Ответ

0 голосов
/ 06 сентября 2018

Скорее всего, вам не хватает оперативной памяти, особенно только с 2 ГБ. Я не профилировал ваш запрос на сервере Postgres, но сначала попробую две вещи:

  1. Во-первых, исправьте ваш запрос (особенно для такого простого запроса), чтобы использовать производный запрос Spring Data JPA или даже запрос Spring Data JPQL:

    public interface ScaleTestRepository extends CrudRepository<ScaleTest, Integer>, ScaleTestRepositoryCustom {
    
        // This is a derived query
        List<ScaleTest> findByWhereTest(BigDecimal whereTest);
    
    }
    
    // Or do...
    
    public interface ScaleTestRepository extends CrudRepository<ScaleTest, Integer>, ScaleTestRepositoryCustom {
    
        // This is a derived query
        @Query("select scaleTest from ScaleTest as scaleTest where where_test > ?")
        List<ScaleTest> findByWhereTest(BigDecimal whereTest);
    
    }
    

Вышеуказанное позволит Spring JPA получить запросы для вас, а затем вы сможете использовать следующее.

  1. Во-вторых, используйте Stream или Flux в качестве типа возврата:

    Stream<ScaleTest> findByWhereTest(BigDecimal whereTest);
    
    // Or do
    
    Flux<ScaleTest> findByWhereTest(BigDecimal whereTest);
    

    Любой из них будет транслироваться (по частям ResultSet), так что вы не будете загружать все эти данные в память и не исчерпывать свою оперативную память.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...