Оптимизация времени отклика [1 findAll () против нескольких findByXYZ () внутри цикла] - PullRequest
0 голосов
/ 28 апреля 2020

У меня есть эта служба, которая выполняет некоторые бухгалтерские расчеты (генерирует годовые отчеты), что несколько сложно, поскольку мы используем формулы, которые затем анализируются и интерпретируются, поэтому сам код java является сложным, но мне удалось оптимизировать его много раз (мы используем SonarQube и codeMetrics), проблема в том, что у меня есть вызов БД внутри a для l oop, и теперь, когда я думаю об этом, это проблема (мне всегда говорили, что операции чтения и записи занимают больше времени, поэтому сокращайте их насколько это возможно) но когда вы видите это, это выглядит безобидно (я просто получаю то, что мне нужно), но недавно мы заметили проблему с производительностью, возможно, это связано с тем, что БД стала больше (хотя я почти уверен, что я провел свои тесты с большие наборы данных) или, может быть, это потому, что мы сейчас находимся в состоянии блокировки и используем VPN, что, возможно, повлияло на время ответа. у меня есть 60 дБ вызовов после окончания цикла), я использовал 2 findAll (), а затем внутри Циклы, в которых я просто использую stream.filter (...) с этим решением, мне удалось удалить около 60 ненужных вызовов в БД и увидеть увеличение времени отклика на 1-2 секунды, иногда на несколько сотен мс, мой вопрос заключается в следующем. хороший подход? или есть переменные, которые я не принимаю во внимание, которые могут быть причиной проблемы? как наличие сервера и базы данных в одной сети против наличия их в двух разных сетях, так и задержка, которая может вызвать ...

До

//1st loop
for(..) {
    ...
    Optional<X> neededXInThisLoop = xDao.findByXYZ(x,y,z);
    ...
}
//2nd loop
for(..) {
    ...
    List<Y> neededYsInThisLoop = yDao.findByX2Y2Z2(x2,y2,z2);
    ...
}

После

List<X> allXs = xDao.findAll();
List<Y> allYs = yDao.findAll();
//1st loop
for(..) {
    ...
    Optional<X> neededXInThisLoop = allXs.stream.filter(...).findFirst();
    ...
}
//2nd loop
for(..) {
    ...
    List<X> neededXsInThisLoop = allXs.stream.filter(...).collect(Collectors.toList());
    ...
}

Ответы [ 2 ]

0 голосов
/ 28 апреля 2020

Позвольте мне попытаться объяснить вам,

В данный момент ваша БД предполагает, что 1000 записей в этом параметре c collection и, используя этот вызов 60 БД, вы фильтруете этот номер с 100 записями. Но только подумайте, что эта таблица содержит 1M записей, и вы применили findALL, поэтому вы получили эти 1М записей, и теперь вы пытаетесь применить эту фильтрующую логи c, используя Java 8 filters Таким образом, этот фильтр сам по себе работает очень медленно с 1M записями.

Так что мое единственное предложение: на данный момент у вас ограниченное количество записей в таблицу, чтобы вы могли видеть улучшение производительности с findALL.

Как только это число увеличится, ваша производительность, безусловно, снизится.

Также вы можете увидеть findByX и findAllByX по указанной ниже ссылке https://spring.io/blog/2017/06/20/a-preview-on-spring-data-kay#improved методы именования для хранилища

0 голосов
/ 28 апреля 2020

Ваша догадка очень верна. После намного эффективнее, чем раньше, и вы должны попытаться свести к минимуму количество вызовов БД в максимально возможной степени (попробуйте сделать столько же в SQL, а затем использовать поток для дальнейшего преобразования результата или тому подобное).

DB Вызывает циклы (или другую повторяющуюся структуру), очень сильно пахнет кодом и может вызвать серьезные проблемы с производительностью.

В идеале вы не должны делать xDao.findAll, а напрямую использовать xDao.findAllByXYZ (), который просто предоставляет вам отфильтрованный список, который вы затем просто сопоставляете с java pojos.

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

Подробнее о том, как Spring поддерживает репозитории JPA, вы можете прочитать, например, в официальной документации Spring . Например, вы можете просто назвать свой метод в JpaRepository findAllBy____ (ваше условие здесь) или использовать аннотацию @Query для указания полноценного SQL или JPQL-запроса, а Spring позаботится обо всем остальном.

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