mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-18 04:08:48 -05:00
d1c3471ba4
- Add ENHANCEMENT_PLAN_IMPLEMENTATION_STATUS.md - Add ENHANCEMENT_PLAN_PROGRESS_SUMMARY.md - Add COMMENT_ATTACHMENTS_IMPLEMENTATION.md - Add COMMENT_ATTACHMENTS_OPTIMIZATION.md - Add FINAL_IMPLEMENTATION_SUMMARY.md Documentation covers all enhancements, implementation status, remaining work, and optimization recommendations.
3.1 KiB
3.1 KiB
Comment Attachments Performance Optimization
Date: 2025-01-27
Status: Recommended Enhancement
Overview
Comment attachments are loaded using a lazy="dynamic" relationship, which means attachments are loaded on-demand when accessed. This can lead to N+1 query problems when displaying multiple comments with attachments.
Current Implementation
Relationship Definition
# app/models/comment_attachment.py
comment = db.relationship("Comment", backref=db.backref("attachments", lazy="dynamic", cascade="all, delete-orphan"))
The lazy="dynamic" means:
comment.attachmentsreturns a query object, not a list- Accessing
comment.attachmentstriggers a database query - Iterating over attachments in templates will work (SQLAlchemy auto-executes), but each comment triggers a separate query
Performance Issue
When displaying a list of comments with attachments:
- Load all comments (1 query)
- For each comment, access
comment.attachments(N queries, one per comment) - Total: 1 + N queries (N+1 problem)
Recommended Solution
Use selectinload() to eager load attachments when querying comments:
Task View Route (Already Updated)
# app/routes/tasks.py - UPDATED
from sqlalchemy.orm import selectinload
all_comments = (
Comment.query.filter_by(task_id=task_id)
.options(
joinedload(Comment.author),
selectinload(Comment.replies).joinedload(Comment.author),
selectinload(Comment.attachments) # Added
)
.order_by(Comment.created_at.asc())
.all()
)
Project Service (Needs Update)
If ProjectService.get_project_view_data() loads comments, it should also eager load attachments:
# In ProjectService.get_project_view_data()
from sqlalchemy.orm import selectinload
comments = (
Comment.query.filter_by(project_id=project_id)
.options(
joinedload(Comment.author),
selectinload(Comment.replies).joinedload(Comment.author),
selectinload(Comment.attachments) # Add this
)
.order_by(Comment.created_at.asc())
.all()
)
Benefits
- Performance: Reduces N+1 queries to 2 queries (comments + attachments)
- Scalability: Works efficiently with many comments
- Consistency: Matches pattern used for replies and authors
Implementation Status
- ✅ Task View Route: Updated to eager load attachments
- ⏳ Project Service: Needs review and update
- ⏳ Quote Comments: Needs review if quotes have comments
- ⏳ API Endpoints: May benefit from eager loading
Testing
After implementing, verify:
- No N+1 queries in database logs
- Comments with attachments load correctly
- Performance improvement with many comments
- No breaking changes to existing functionality
Notes
selectinload()is preferred overjoinedload()for one-to-many relationships (like attachments)selectinload()uses a separate SELECT IN query, which is more efficient than joins for collections- The dynamic relationship still works for programmatic access, but templates benefit from eager loading