이 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 |