【Spring】Spring JPQLで結合する場合に気をつけること【JPQL】

JPA
  • 部屋(Room)テーブルと備品(Equipment)テーブルがあり、それぞれ1対多のリレーションがあるとする。
  • JPQLでの結合をしてみる。
package com.example.demo.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.example.demo.entity.Room;

public interface RoomRepository extends JpaRepository<Room, Integer> {

    @Query("SELECT r FROM Room r LEFT OUTER JOIN r.equipments")
    List<Room> find();
}

独特な構文だが、この書き方の場合、RoomテーブルをSELECTした後に、Equipmentテーブルを1件ずつ取得する、いわゆるN+1問題が発生する。

①Roomテーブルのselect 
select
 r1_0.room_id,
 r1_0.invalid,
 r1_0.room_name 
from
  room r1_0 left join equipment e1_0 on r1_0.room_id=e1_0.room_id

②①で取得したRoomテーブルのレコードのうち、
Equipmentテーブルに紐づくレコードがある場合、都度selectを行う。

select
 e1_0.room_id,
 e1_0.equipment_id,
 e1_0.equipment_name,
 e1_0.invalid 
from
  equipment e1_0 
where
  e1_0.room_id=?

binding parameter [1] as [INTEGER] - [1]

select
 e1_0.room_id,
 e1_0.equipment_id,
 e1_0.equipment_name,
 e1_0.invalid 
from
  equipment e1_0 
where
  e1_0.room_id=?

binding parameter [1] as [INTEGER] - [2]

select
 e1_0.room_id,
 e1_0.equipment_id,
 e1_0.equipment_name,
 e1_0.invalid 
from
  equipment e1_0 
where
  e1_0.room_id=?

binding parameter [1] as [INTEGER] - [3k]
  • これを防ぐにはJOIN FETCHを行う。
package com.example.demo.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.example.demo.entity.Room;

public interface RoomRepository extends JpaRepository<Room, Integer> {

    @Query("SELECT r FROM Room r LEFT OUTER JOIN FETCH r.equipments")
    List<Room> find();
}
  • 実行結果を見ると一度のクエリで結合情報を取得できていた。
select
  r1_0.room_id,
  e1_0.room_id,
  e1_0.equipment_id,
  e1_0.equipment_name,
  e1_0.invalid,
  r1_0.invalid,
  r1_0.room_name 
from
  room r1_0 left join equipment e1_0 
  on r1_0.room_id=e1_0.room_id
  • よほどの理由がない限り、JPQLで結合を行うときはFETCHをつけること。

コメント

タイトルとURLをコピーしました