perf(feed): Batch load media and tags to fix N+1 query
Per v1.5.0 Phase 3: Fix N+1 query pattern in feed generation. Implementation: - Add get_media_for_notes() to starpunk/media.py for batch media loading - Add get_tags_for_notes() to starpunk/tags.py for batch tag loading - Update _get_cached_notes() in starpunk/routes/public.py to use batch loading - Add comprehensive tests in tests/test_batch_loading.py Performance improvement: - Before: O(n) queries (1 query per note for media + 1 query per note for tags) - After: O(1) queries (2 queries total: 1 for all media, 1 for all tags) - Maintains same API behavior and output format All tests passing: 920 passed in 360.79s 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -42,11 +42,13 @@ def _get_cached_notes():
|
||||
Returns cached notes if still valid, otherwise fetches fresh notes
|
||||
from database and updates cache. Includes media and tags for each note.
|
||||
|
||||
Per v1.5.0 Phase 3: Uses batch loading to avoid N+1 query pattern.
|
||||
|
||||
Returns:
|
||||
List of published notes for feed generation (with media and tags attached)
|
||||
"""
|
||||
from starpunk.media import get_note_media
|
||||
from starpunk.tags import get_note_tags
|
||||
from starpunk.media import get_media_for_notes
|
||||
from starpunk.tags import get_tags_for_notes
|
||||
|
||||
# Get cache duration from config (in seconds)
|
||||
cache_seconds = current_app.config.get("FEED_CACHE_SECONDS", 300)
|
||||
@@ -64,13 +66,18 @@ def _get_cached_notes():
|
||||
max_items = current_app.config.get("FEED_MAX_ITEMS", 50)
|
||||
notes = list_notes(published_only=True, limit=max_items)
|
||||
|
||||
# Attach media to each note (v1.2.0 Phase 3)
|
||||
# Batch load media and tags for all notes (v1.5.0 Phase 3)
|
||||
# Reduces query count from O(n) to O(1) for both media and tags
|
||||
note_ids = [note.id for note in notes]
|
||||
media_by_note = get_media_for_notes(note_ids)
|
||||
tags_by_note = get_tags_for_notes(note_ids)
|
||||
|
||||
# Attach media and tags to each note
|
||||
for note in notes:
|
||||
media = get_note_media(note.id)
|
||||
media = media_by_note.get(note.id, [])
|
||||
object.__setattr__(note, 'media', media)
|
||||
|
||||
# Attach tags to each note (v1.3.1)
|
||||
tags = get_note_tags(note.id)
|
||||
tags = tags_by_note.get(note.id, [])
|
||||
object.__setattr__(note, '_cached_tags', tags)
|
||||
|
||||
_feed_cache["notes"] = notes
|
||||
|
||||
Reference in New Issue
Block a user