Skip to content

Commit 8fb6414

Browse files
acailicclaude
andcommitted
fix: eliminate N+1 queries in _load_candidate_sessions event_type filter (#132)
Replace the Python loop that issued one SQL query per session when filtering by event_type with a single IN subquery pushed into the initial session SELECT. Query count drops from O(n) to O(1) regardless of the number of candidate sessions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9f4328e commit 8fb6414

1 file changed

Lines changed: 13 additions & 18 deletions

File tree

storage/search.py

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -315,28 +315,23 @@ async def _load_candidate_sessions(
315315
if tag_conditions:
316316
stmt = stmt.where(or_(*tag_conditions))
317317

318-
result = await self.session.execute(stmt)
319-
sessions = list(result.scalars().all())
320-
321-
# Filter by event_type if specified (requires checking events)
318+
# Filter by event_type in SQL using a subquery to avoid N+1 queries.
319+
# Previously this was done with a Python loop issuing one query per session.
322320
if event_type:
323-
sessions_with_event_type = []
324-
for session in sessions:
325-
# Check if session has any event of the specified type
326-
# Handle both string and enum values
327-
event_type_str = event_type.value if hasattr(event_type, 'value') else event_type
328-
329-
event_stmt = select(EventModel).where(
330-
EventModel.session_id == session.id,
321+
event_type_str = event_type.value if hasattr(event_type, "value") else event_type
322+
event_subq = (
323+
select(EventModel.session_id)
324+
.where(
331325
EventModel.tenant_id == self.tenant_id,
332326
EventModel.event_type == event_type_str,
333-
).limit(1)
334-
event_result = await self.session.execute(event_stmt)
335-
if event_result.scalar_one_or_none() is not None:
336-
sessions_with_event_type.append(session)
337-
sessions = sessions_with_event_type
327+
)
328+
.distinct()
329+
.scalar_subquery()
330+
)
331+
stmt = stmt.where(SessionModel.id.in_(event_subq))
338332

339-
return sessions
333+
result = await self.session.execute(stmt)
334+
return list(result.scalars().all())
340335

341336
async def _score_sessions(
342337
self,

0 commit comments

Comments
 (0)