Как ускорить маппинг записей из БД в объекты Java?

Всем привет, прошу помочь советом. Очень долго маппятся записи из БД в объекты Java. Имеем следующее: БД - Oracle SQL. Язык - Java 1.8. Имеем два класса (пишу примерно, синтаксис может хромать):

public class Person {
    private Long id;    
    private String name;
    private String uuid;
    private List<Article> articleList;
    ...
    ...
    private Date cDate;
    private Date uDate;
}
public class Article {
    private Long id;
    private String title;
    private String uuid;
    ...
    ...
    private Date cDate;
    private Date uDate;
}

В каждом классе примерно по 10 полей (String, Long, Date), общее поле uuid (примерно такого формата 123e4567-e89b-12d3-a456-426655440000, соответственно, в таблице person это поле уникально для каждой строки, а в таблице article может быть несколько записей с одинаковым uuid, которое указывает на конкретного человека из таблицы person). В БД в таблице person около 300 записей, а в таблице article около 35000 строк. Для каждого из person в среднем от 1 до 300 строк из таблицы article. Мне нужно достать из обеих таблиц всех person с их списками article. Я не так давно начал свой путь в разработке, поэтому не знаю самых оптимальных вариантов выборки и маппинга объектов из БД. В связи с этим имею довольно неудовлетворительные результаты по времени выборки данных из БД. Сначала достаю все объекты из таблицы person. Потом все записи из таблицы article. Дальше раскидываю все article по спискам для каждого из людей. Но когда я даже просто достаю все записи из таблицы article и создаю объекты Article, то этот процесс занимает около 20 секунд. Если отправлять запрос просто в DBeaver, то выборка происходит почти моментально. Но в java объекты создаются 20 секунд. Написан обычный ArticleRowmapper, реализующий Rowmapper. Вроде ничего сверхестественного..

Метод выборки тоже самый обычный:

   public List<Article> getAllArticles() {
      String SQL = "select * from article";
      List <Article> articles = jdbcTemplateObject.query(SQL, new ArticleRowMapper());
      return articles;
   }

Конечно, было бы идеально, если бы можно было вытянуть из БД одним запросом всех person и чтобы они уже были со списками своих article, но не знаю, возможно ли это.. Буду благодарен, если кто-либо подскажет как можно ускорить выборку строк article и маппинг их в объекты Java.


Ответы (1 шт):

Автор решения: Roman Konoval

Проблема, скорее всего, в количестве данных, а именно в том, что, вероятно, у вас в Article хранится текст статьи.

Я провел у себя эксперимент с 35к записями. Если в Article есть одно поле с 10 килобайтной строкой - то время чтения 35к записей как раз около 20 секунд. Если же это поле исключить, то получается 250 мс.

Время запроса в DBeaver - не показатель, так как там скорее всего не читаются все данные из таблицы, они подгружаются по мере необходимости, когда вы скролите таблицу. Время занимает пересылка данных, а сам запрос, то есть без итерации по всем строкам и, соответственно, без пересылки данных на сторону java и в jdbc выполняется быстро, если установить fetchSize в какое-то разумное значение, чтоб не читать все данные сразу.

Когда вы отображаете список всего, то вам содержимое (текст) статьи скорее всего не нужен. Измените запрос, чтоб он в результат не включал поле с текстом статьи (а в мапер передавайте флаг, который будет указывать, что это поле не нужно из ResulstSet читать и, соответственно, не заполнять поле в объекте Article):

public static final boolean READ_ARTICLE_CONTENT = true;


public List<Article> getAllArticles() {
      String SQL = "select id, title, uuid, ..., cdate, udate from article";
      List <Article> articles = jdbcTemplateObject.query(SQL, new ArticleRowMapper(!READ_ARTICLE_CONTENT));
      return articles;
}


class ArticleRowMapper implements RowMapper<Article> {
  private boolean readContent;
  public ArticleRowMapper(boolean readContent) {
    this.readContent = readContent;
  }

  @Override
  public Article mapRow(ResultSet rs, int rownum) throws SQLException {
    Article article = new Article();

    article.setId(rs.getInt("id"));
    ...
    // я тут предполагаю, что поле называется content
    if (readContent) {
      article.setContent(rs.getString("content"));
    }
  }
};
→ Ссылка