@OneToOne делает sql запрос на каждый объект в таблице
Всем привет, сделал необходимые entity под БД:
@Getter
@Setter
@Accessors(chain = true)
@Entity
@Table(name = "****", schema = "****")
public class ShopProductEntity implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "id", nullable = false)
private Integer id;
@OneToOne
@JoinColumn(name = "sku_id", referencedColumnName = "id")
private ShopProductSkusEntity sku;
}
@Getter
@Setter
@Accessors(chain = true)
@Entity
@Table(name = "****", schema = "*****")
public class ShopProductSkusEntity implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "id", nullable = false)
private Integer id;
@Basic
@Column(name = "product_id", nullable = false)
private Integer productId;
@Basic
@Column(name = "sku", nullable = false, length = 255)
private String sku;
}
И когда делаю запрос на получение всех элементов таблицы:
public synchronized List<ShopProductEntity> getAllProducts() {
return em.createQuery("SELECT a FROM ShopProductEntity a", ShopProductEntity.class)
.getResultList();
}
То вижу по логам Hibernate, что происходит первый запрпос на получение всех строк из ShopProductEntity, а потом для каждой записи - происходит отдельный запрос в ShopProductSkusEntity:
Hibernate: select shopproduc0_.id as id1_4_, shopproduc0_.sku_id as sku_id2_4_ from shop_product shopproduc0_
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
Hibernate: select shopproduc0_.id as id1_7_0_, shopproduc0_.product_id as product_2_7_0_, shopproduc0_.sku as sku3_7_0_ from shop_product_skus shopproduc0_ where shopproduc0_.id=?
и так далее . . .
А записей в ShopProductEntity порядка 180000 и Hibernate делает запросы не паралельно, а в одном потоке. И каждый запрос занимает где-то 0.2-0.3 мс, что приводит к неопределенному кол-во времени в ожидании, пока всё выгрузиться (явно более 1 часа).
Вопрос: Как оптимизировать этот момент? Может как-то можно указать Hibernate, чтобы он кэшировал сразу всю таблицу ShopProductSkusEntity и не обращался постоянно к БД? Или есть какие-то другие варианты, может это проблема N+1 и надо копать в эту сторону?
Ответы (1 шт):
Исходя из комментариев под вопросом (спасибо Дмитрию и MrFylypenko) - выявил 2 решения, которые одинаково хорошо решают мою проблему:
- Принудительно использовать в HQL запросе left join fetch, что заставить Hibernate добавить в свой запрос left outer join и сразу выгрузить все необходимые строки из другой таблицы, вместо того чтобы делать отдельный запрос на каждую строку
- Просто использовать @ManyToOne