피드로 돌아가기
Set-Based Updates in Rails: 4 Hours to 8 Seconds
Dev.toDev.to
Database

N+1 Update 제거를 통한 처리 시간 4시간에서 8초로 단축

Set-Based Updates in Rails: 4 Hours to 8 Seconds

Wilbur Suero2026년 5월 12일7intermediate

Context

ActiveRecord의 루프 내 개별 업데이트 방식으로 인한 N+1 Query 발생 상황. 50,000건의 데이터 처리 시 과도한 DB Transaction 생성으로 2GB RAM 소비 및 타임아웃 발생.

Technical Solution

  • Application 레벨의 객체 로딩을 배제하고 Database 레벨에서 직접 연산을 수행하는 Set-Based Update 구조로 전환
  • update_all을 통한 단일 SQL UPDATE 구문 생성으로 네트워크 Round-trip 및 트랜잭션 오버헤드 최소화
  • updated_at 컬럼의 수동 갱신 설계를 통해 ActiveRecord Lifecycle 우회로 인한 캐시 무효화 실패 문제 해결
  • in_batches를 활용한 데이터 분할 처리로 대량 업데이트 시 발생하는 Row Locking 시간 단축 및 동시성 확보
  • CASE 구문과 sanitize_sql_array를 조합하여 개별 레코드별 서로 다른 값을 안전하고 효율적으로 업데이트하는 Heterogeneous Update 구현

Impact

  • 데이터 처리 시간: 4시간 → 8초로 단축
  • 페이지 로딩 속도: 20초 → 200ms로 개선 (View Count 증분 처리 기준)

Key Takeaway

비즈니스 로직 검증이나 콜백 실행이 불필요한 대량 데이터 변경 시에는 Application 중심의 객체 지향 업데이트보다 Database 중심의 집합 기반 업데이트가 압도적 성능을 제공함.


- `.each` 루프 내부에서 `update` 호출 여부 확인 - `update_all` 사용 시 `updated_at` 수동 갱신 및 Callback 누락 여부 검토 - 대규모 업데이트 시 `in_batches` 적용을 통한 DB Lock 범위 제한 - 복합 값 업데이트 시 SQL Injection 방지를 위한 `sanitize_sql_array` 적용

원문 읽기