본문 바로가기

Ruby On Rails/Model(ORM)

preload vs includes vs eager_load vs joins

이 4가지의 차이점을 살펴보겠다.

 

1. preload

  • 연관관계에 있는 테이블을 미리 로드해준다.
  • includes와 default는 같지만 약간의 차이가 있다.
  • 연관관계 로드할 때, 항상 query를 분리해서 요청한다.
store = '도매'
wholesale_stores = WholesaleStore.preload(store_number: [building_floor: :building]).where('store LIKE ?', "%#{store}%")

이렇게 호출하면 쿼리가.

WholesaleStore Load (44.5ms)  SELECT `wholesaleStore`.* FROM `wholesaleStore` WHERE (store LIKE '%도매%')
  StoreNumber Load (30.6ms)  SELECT `storeNumber`.* FROM `storeNumber` WHERE `storeNumber`.`id` IN (25546, 18017136, 16221, 18172)
  BuildingFloor Load (47.2ms)  SELECT `buildingFloor`.* FROM `buildingFloor` WHERE `buildingFloor`.`id` IN (1, 3, 4, 8)
  Building Load (64.9ms)  SELECT `building`.* FROM `building` WHERE `building`.`id` IN (1, 2, 5, 6)

이렇게 연관관계에 속해있는 모든 테이블에 쿼리를 날린다.

 

그리고 만약에, 연관관계 테이블을 조건절에 넣는다면,

store = '도매'
wholesale_stores = WholesaleStore.preload(store_number: [building_floor: :building]).where(store_number: {id: 14})

이 호출에 대한 쿼리는,

WholesaleStore Load (13.7ms)  SELECT `wholesaleStore`.* FROM `wholesaleStore` WHERE (storeNumber.id = 14)
  WholesaleStore Load (55.2ms)  SELECT `wholesaleStore`.* FROM `wholesaleStore` WHERE (storeNumber.id = 14) LIMIT 11

즉, 연관관계에 있는 쿼리를 호출하지 못한다. 그러므로 항상 연관관계에 있는 쿼리를 호출하면 안 되고 자기 자신의 조건절을 사용해서 preload()를 사용해야 한다.

 

2. includes

  • 연관관계에 있는 테이블을 미리 로드해준다.
  • 연관관계를 로드할 때, 테이블을 분리해서 쿼리를 요청하는 것이 디폴트이다.
  • 만약에 연관관계의 조건절을 사용하면, left join을 사용한다.

첫 번째 테이블을 분리해서 쿼리를 요청하는 것은 preload와 동일한 결괏값을 리턴하므로 생략하겠다.

두 번째 left join이 날아가는 경우만 확인해보자.

store = '도매'
wholesale_stores = WholesaleStore.includes(:store_number).where(store_number: {id: 14})

이 호출에 대한 쿼리는,

SELECT `wholesaleStore`.`*`, `storeNumber`.`*` FROM `wholesaleStore` 
LEFT OUTER JOIN `storeNumber` ON `storeNumber`.`id` = `wholesaleStore`.`sn_id` 
WHERE `store_number`.`id` = 14

이렇게 레프트 조인을 사용하게 된다.

 

3. eager_load

  • eager_load() 메서드를 사용하면, left join을 사용해서 데이터를 가져온다.
  • 이 메서드를 사용하면 위에 includes()에서 left join이 날아간 것처럼 쿼리가 날아간다.
  • 실무에선 쓸 일이 없다. 왜냐하면 left join은 꼭 필요한 경우만 사용해야 하고, 쓸 일이 있을 땐, left_outer_joins()라는 메서드를 액티브 레코드가 제공하기 때문이다.

4. joins

  • inner join을 요청한다.
  • 그래서 연관된 데이터를 한 번의 쿼리로 가져온다.
  • select 메서드를 필수적으로 같이 사용해야 제대로 쓸 수 있다.
@sheets = SheetGood.get_data(ids)

class SheetGood
  scope :get_data, -> (ids) {
    joins(:order_sheet)
      .joins(sheet_goods_infos: [store_goods_infos: [sheet_store: [w_sheet: :w_sheet_group]]])
      .left_joins(s_sheet: :stop_order)
      .where("wSheetGroup.status != 'Deleted'")
      .where(id: ids)
      .select('sSheet.id as sId,
            sSheet.od,
            sSheet.ie,
            sSheet.wsId,
            sSheet.gId,
            sSheet.rsId,
            sSheet.type,
            sheetGoods.gn,
            sheetGoodsInfo.col,
            sheetGoodsInfo.size,
            sheetGoodsInfo.price,
            sheetGoodsInfo.count,
            stop_orders.status AS stopOS')
  }
end

이렇게 쿼리를 요청하면 내부적으로 inner join을 사용하여 한 번에 가져온다.

'Ruby On Rails > Model(ORM)' 카테고리의 다른 글

find_in_batches vs each_slice  (0) 2021.12.25
batches를 사용하는 이유  (0) 2021.12.25
Model 정리  (0) 2021.12.24