ActiveRecord OUTER JOIN UPDATE 개선 사항
ActiveRecord에서 OUTER JOIN을 포함한 UPDATE 문 처리 방식은 PostgreSQL 및 SQLite 환경에서 중요한 변화를 겪었습니다. 이 변화는 특히 ON 절에서 업데이트 대상 테이블을 참조할 때 발생했던 비효율성을 해결하기 위한 것입니다.
변경 전: 서브쿼리 방식의 한계
이전에는 OUTER JOIN을 사용하여 UPDATE를 수행하고 ON 절에서 업데이트될 테이블을 참조할 경우, Rails는 안전하게 WHERE 절로 이동할 수 없는 조인 조건을 처리하기 위해 서브쿼리를 생성했습니다.
예시 코드 (Ruby):
ruby
Client.joins("LEFT JOIN projects ON projects.client_id = clients.id")
.where("projects.id IS NULL")
.update_all(name: 'Archived Client')
생성된 SQL (변경 전):
sql
UPDATE "clients"
SET "name" = 'Archived Client'
WHERE ("clients"."id") IN (
SELECT "clients"."id"
FROM "clients"
LEFT JOIN projects ON projects.client_id = clients.id
WHERE (projects.id IS NULL)
)
이 방식은 특히 대규모 데이터셋에서 효율성이 떨어지고, 불필요한 서브쿼리로 인해 SQL이 복잡해지며 최적화가 어려웠습니다.
변경 후: 셀프 조인(Self-Join) 방식 도입
이제 Rails는 PostgreSQL 및 SQLite에서 OUTER JOIN을 사용한 UPDATE 시 서브쿼리 대신 셀프 조인(self-join)을 활용합니다. 이는 업데이트 대상 테이블을 FROM 절에 별칭과 함께 추가하고, 기본 키를 기준으로 셀프 조인을 수행하는 방식입니다.
생성된 SQL (변경 후):
sql
UPDATE "clients" AS "__active_record_update_alias"
SET "name" = 'Archived Client'
FROM "clients"
LEFT JOIN projects ON projects.client_id = clients.id
WHERE (projects.id IS NULL)
AND "clients"."id" = "__active_record_update_alias"."id"
이 새로운 접근 방식은 서브쿼리를 제거하여 SQL을 더 간결하게 만들고, 실행 계획을 단순화하여 전반적인 성능을 향상시킵니다. 업데이트 작업의 효율성을 높이고 데이터베이스 부하를 줄이는 데 기여합니다.