본문으로 건너뛰기

[Open WebUI] SCIM 그룹 변환에서 N+1 쿼리를 배치 조회로 제거

PR 링크: open-webui/open-webui#21005 상태: Merged | 변경: +11 / -12

들어가며

SCIM(System for Cross-domain Identity Management)은 사용자와 그룹 정보를 표준화된 형식으로 외부 시스템에 제공하는 프로토콜이다. Open WebUI의 group_to_scim 함수는 내부 그룹 모델을 SCIM 포맷으로 변환하는데, 기존 구현에서는 그룹 멤버 한 명마다 get_user_by_id를 개별 호출하는 전형적인 N+1 쿼리 패턴이 있었다. 그룹 멤버가 100명이면 101개의 쿼리가 발생하는 구조였다.

핵심 코드 분석

Before: 멤버마다 개별 쿼리

member_ids = Groups.get_group_user_ids_by_id(group.id, db) or []
members = []

for user_id in member_ids:
    user = Users.get_user_by_id(user_id, db=db)  # N번 쿼리
    if user:
        members.append(
            SCIMGroupMember(
                value=user.id,
                ref=f"{request.base_url}api/v1/scim/v2/Users/{user.id}",
                display=user.name,
            )
        )

After: 단일 배치 조회

member_ids = Groups.get_group_user_ids_by_id(group.id, db) or []

# Batch-fetch all users to avoid N+1 queries
users = Users.get_users_by_user_ids(member_ids, db=db) if member_ids else []
members = [
    SCIMGroupMember(
        value=user.id,
        ref=f"{request.base_url}api/v1/scim/v2/Users/{user.id}",
        display=user.name,
    )
    for user in users
]

왜 이게 좋은가

  1. 쿼리 수 감소: N+1 쿼리가 단 1개의 SQL IN 절 쿼리로 줄어든다. 멤버가 몇 명이든 데이터베이스 왕복은 한 번이다.
  2. 코드 간결성: for 루프와 조건문이 리스트 컴프리헨션으로 대체되어 의도가 명확해졌다.
  3. 빈 리스트 가드: if member_ids 조건으로 멤버가 없을 때 불필요한 쿼리 자체를 방지한다.

N+1 문제는 ORM 기반 웹 애플리케이션에서 가장 흔한 성능 함정 중 하나다. 이 PR은 기존에 존재하던 get_users_by_user_ids 배치 메서드를 활용하는 것만으로 문제를 깔끔하게 해결했다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글