From 968df8150a36820af1915e7677adc4724d372efa Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Apr 2026 13:55:14 +0000 Subject: [PATCH] perf(channels): batch user lookup in model_response_handler thread history The thread-history builder in model_response_handler called Users.get_user_by_id once per thread message (deduped via an intra-loop dict), producing N individual SELECTs for a thread of N unique authors. Replace with a single Users.get_users_by_user_ids call that returns all authors in one WHERE id IN (...) query, matching the batch pattern already used elsewhere in this file (lines 739, 804, 1320). Behavior is preserved: deleted users still resolve to None and fall through to the existing 'Unknown' fallback via .get(). --- backend/open_webui/routers/channels.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index a771b95920..08f3615cda 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -923,15 +923,13 @@ async def model_response_handler(request, channel, message, user, db=None): thread_history = [] images = [] - message_users = {} + + # Batch fetch all users in a single query (fixes N+1 problem) + user_ids = list({m.user_id for m in thread_messages}) + message_users = {u.id: u for u in await Users.get_users_by_user_ids(user_ids, db=db)} for thread_message in thread_messages: - message_user = None - if thread_message.user_id not in message_users: - message_user = await Users.get_user_by_id(thread_message.user_id, db=db) - message_users[thread_message.user_id] = message_user - else: - message_user = message_users[thread_message.user_id] + message_user = message_users.get(thread_message.user_id) if thread_message.meta and thread_message.meta.get('model_id', None): # If the message was sent by a model, use the model name