[Open WebUI] 채팅 제목 조회 시 전체 대화 로드 대신 title 컬럼만 직접 쿼리
PR 링크: open-webui/open-webui#21590 상태: Merged | 변경: +5 / -5
들어가며
Open WebUI의 get_chat_title_by_id 함수는 채팅의 제목만 필요한데, 전체 ChatModel을 로드하고 있었습니다. ChatModel에는 전체 대화 히스토리가 JSON blob으로 포함되어 있어, 수백 개의 메시지가 있는 채팅에서는 불필요한 데이터를 대량으로 읽어오는 셈이었습니다.
핵심 코드 분석
Before: 전체 모델 로드
def get_chat_title_by_id(self, id: str) -> Optional[str]:
chat = self.get_chat_by_id(id) # SELECT * FROM chat WHERE id = ?
if chat is None:
return None
return chat.chat.get("title", "New Chat")
get_chat_by_id는 SELECT *로 전체 행을 가져오고, ORM이 이를 ChatModel로 변환한 후, 거대한 JSON blob에서 title을 추출합니다.
After: title 컬럼만 쿼리
def get_chat_title_by_id(self, id: str) -> Optional[str]:
with get_db_context() as db:
result = db.query(Chat.title).filter_by(id=id).first()
# SELECT title FROM chat WHERE id = ?
if result is None:
return None
return result[0] or "New Chat"
왜 이게 좋은가
1. 디스크 I/O 절감
SELECT *는 대화 히스토리가 포함된 JSON blob 전체를 디스크에서 읽습니다. 수백 턴의 대화에서 이 blob은 수 MB에 달할 수 있습니다. SELECT title은 인덱스 스캔만으로 완료될 수 있어 I/O가 극적으로 줄어듭니다.
2. 네트워크 대역폭 절약
원격 데이터베이스를 사용하는 배포 환경에서, 제목 문자열 하나를 위해 MB 단위의 JSON blob을 전송하는 것은 네트워크 낭비입니다.
3. 호출 사이트 분석
이 함수는 middleware.py에서 2곳(라인 2927, 4432)에서 호출됩니다. 응답 완료 후 알림/로깅 목적으로 사용되므로 호출 빈도는 높지 않지만, 각 호출의 비용이 크기 때문에 최적화 효과가 있습니다.
4. ORM 역직렬화 비용 제거
전체 모델을 로드하면 SQLAlchemy의 model_validate가 JSON blob을 파이썬 딕셔너리로 파싱합니다. 컬럼 쿼리는 이 과정을 완전히 건너뜁니다.
참고 자료
- SQLAlchemy: Column-level queries — 특정 컬럼만 조회하는 방법
- PostgreSQL TOAST — 큰 필드가 별도 저장되는 메커니즘
관련 포스트
PR Analysis 의 다른글
- 이전글 [Open WebUI] O(n²) 시간 복잡도 메시지 리스트 생성 버그 수정
- 현재글 : [Open WebUI] 채팅 제목 조회 시 전체 대화 로드 대신 title 컬럼만 직접 쿼리
- 다음글 [Open WebUI] 채팅 목록 조회 시 불필요한 전체 JSON 로딩 제거
댓글