11 changed files with 450 additions and 27 deletions
-
134OPTIMIZATION_PLAN.md
-
122apps/course/migrations/0005_add_database_indexes.py
-
15apps/course/models/course.py
-
28apps/course/models/lesson.py
-
8apps/course/models/participant.py
-
50apps/course/serializers/course.py
-
12apps/course/serializers/lesson.py
-
58apps/course/views/course.py
-
36apps/course/views/lesson.py
-
7apps/course/views/participant.py
-
7apps/video/views.py
@ -0,0 +1,134 @@ |
|||
# Django Database Query Optimization Plan |
|||
|
|||
## Phase 1: Analysis Complete ✅ |
|||
|
|||
### Current Issues Identified: |
|||
1. **N+1 Query Problems** in course, video, library, article, podcast views |
|||
2. **Missing select_related/prefetch_related** optimizations |
|||
3. **Inefficient serializer methods** with individual database queries |
|||
4. **Missing database indexes** on frequently queried fields |
|||
5. **Suboptimal queryset patterns** in views and admin |
|||
|
|||
## Phase 2: Query Optimization Implementation Plan |
|||
|
|||
### Step 1: Course App Optimization |
|||
**Priority: HIGH** (Core functionality) |
|||
|
|||
#### 1.1 Course Views Optimization |
|||
- **CourseListAPIView**: Add select_related for professor, category |
|||
- **CourseDetailAPIView**: Add prefetch_related for lessons, attachments, glossaries, participants |
|||
- **MyCourseListAPIView**: Optimize participant and completion queries |
|||
|
|||
#### 1.2 Course Serializers Optimization |
|||
- **CourseListSerializer**: Optimize professor and category access |
|||
- **CourseDetailSerializer**: Optimize all related object access |
|||
- **CourseLessonSerializer**: Optimize lesson completion and quiz queries |
|||
|
|||
#### 1.3 Course Admin Optimization |
|||
- **CourseAdmin**: Add select_related/prefetch_related to get_queryset |
|||
- **ParticipantAdmin**: Optimize student and course queries |
|||
|
|||
### Step 2: Video App Optimization |
|||
**Priority: HIGH** (Heavy content usage) |
|||
|
|||
#### 2.1 Video Views Optimization |
|||
- **VideoListAPIView**: Add prefetch_related for categories, collections |
|||
- **VideoDetailAPIView**: Optimize playlist and bookmark queries |
|||
- **VideoCollectionViews**: Optimize video relationships |
|||
|
|||
#### 2.2 Video Serializers Optimization |
|||
- **VideoDetailSerializer**: Optimize bookmark, rate, and playlist queries |
|||
- **VideoCollectionSerializer**: Optimize video access |
|||
|
|||
### Step 3: Library App Optimization |
|||
**Priority: HIGH** (Heavy content usage) |
|||
|
|||
#### 3.1 Library Views Optimization |
|||
- **BookListView**: Add prefetch_related for categories, collections |
|||
- **BookDetailView**: Optimize bookmark and rate queries |
|||
- **BookCollectionViews**: Optimize book relationships |
|||
|
|||
#### 3.2 Library Serializers Optimization |
|||
- **BookSerializer**: Optimize bookmark and rate queries |
|||
- **BookCollectionSerializer**: Optimize book access |
|||
|
|||
### Step 4: Article & Podcast Apps Optimization |
|||
**Priority: MEDIUM** |
|||
|
|||
#### 4.1 Similar patterns to Video/Library apps |
|||
- Apply same optimization patterns |
|||
- Focus on category and collection relationships |
|||
- Optimize bookmark and rate queries |
|||
|
|||
### Step 5: Account App Optimization |
|||
**Priority: MEDIUM** |
|||
|
|||
#### 5.1 User Admin Optimization |
|||
- **UserAdmin**: Already has some prefetch_related, enhance further |
|||
- **StudentUserAdmin**: Optimize course participation queries |
|||
|
|||
### Step 6: Chat App Optimization |
|||
**Priority: MEDIUM** |
|||
|
|||
#### 6.1 Chat Views Optimization |
|||
- **RoomMessage queries**: Add select_related for initiator, recipient, course |
|||
- **ChatMessage queries**: Add select_related for sender, room |
|||
|
|||
### Step 7: Bookmark & Rate System Optimization |
|||
**Priority: HIGH** (Used across all content types) |
|||
|
|||
#### 7.1 Bookmark Queries Optimization |
|||
- Optimize bookmark status checks in serializers |
|||
- Add bulk bookmark queries where possible |
|||
|
|||
## Phase 3: Database Indexing Plan |
|||
|
|||
### Step 1: Primary Indexes |
|||
- Add indexes on status fields (all models) |
|||
- Add indexes on created_at, updated_at fields |
|||
- Add indexes on slug fields |
|||
|
|||
### Step 2: Foreign Key Indexes |
|||
- Ensure all ForeignKey fields have indexes |
|||
- Add composite indexes for common query patterns |
|||
|
|||
### Step 3: Composite Indexes |
|||
- (user_id, service, status) for Bookmark model |
|||
- (course_id, student_id) for Participant model |
|||
- (status, created_at) for content models |
|||
|
|||
## Phase 4: Implementation Order |
|||
|
|||
### Week 1: Course App (Core functionality) |
|||
1. Course views optimization |
|||
2. Course serializers optimization |
|||
3. Course admin optimization |
|||
4. Add course-related indexes |
|||
|
|||
### Week 2: Content Apps (Video, Library) |
|||
1. Video app optimization |
|||
2. Library app optimization |
|||
3. Add content-related indexes |
|||
|
|||
### Week 3: Remaining Apps |
|||
1. Article and Podcast apps |
|||
2. Account app enhancements |
|||
3. Chat app optimization |
|||
4. Bookmark system optimization |
|||
|
|||
### Week 4: Final Optimizations |
|||
1. Remaining indexes |
|||
2. Performance testing |
|||
3. Query analysis and fine-tuning |
|||
|
|||
## Success Metrics |
|||
- Reduce average response time by 50-70% |
|||
- Reduce database query count per request by 60-80% |
|||
- Maintain exact same API response format |
|||
- Zero breaking changes to existing functionality |
|||
|
|||
## Implementation Strategy |
|||
- One optimization at a time |
|||
- Test each change individually |
|||
- Maintain backward compatibility |
|||
- Monitor performance improvements |
|||
@ -0,0 +1,122 @@ |
|||
# Generated by Django 5.1.8 on 2025-06-11 19:21 |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('account', '0003_locationhistory'), |
|||
('course', '0004_alter_attachment_options_alter_glossary_options_and_more'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterModelOptions( |
|||
name='courselesson', |
|||
options={'verbose_name': 'Course Lesson', 'verbose_name_plural': 'Course Lessons'}, |
|||
), |
|||
migrations.AlterModelOptions( |
|||
name='lesson', |
|||
options={'verbose_name': 'Lesson', 'verbose_name_plural': 'Lessons'}, |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='course', |
|||
index=models.Index(fields=['status'], name='course_cour_status_57ffd9_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='course', |
|||
index=models.Index(fields=['is_free'], name='course_cour_is_free_9453a1_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='course', |
|||
index=models.Index(fields=['created_at'], name='course_cour_created_49f06e_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='course', |
|||
index=models.Index(fields=['slug'], name='course_cour_slug_235a66_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='course', |
|||
index=models.Index(fields=['status', 'created_at'], name='course_cour_status_bfcd24_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='course', |
|||
index=models.Index(fields=['category', 'status'], name='course_cour_categor_26bb4d_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='course', |
|||
index=models.Index(fields=['professor', 'status'], name='course_cour_profess_5eae9a_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='courseattachment', |
|||
index=models.Index(fields=['course'], name='course_cour_course__106cc8_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='courseattachment', |
|||
index=models.Index(fields=['attachment'], name='course_cour_attachm_2da12a_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='courselesson', |
|||
index=models.Index(fields=['course'], name='course_cour_course__4afa4c_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='courselesson', |
|||
index=models.Index(fields=['lesson'], name='course_cour_lesson__e5c835_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='courselesson', |
|||
index=models.Index(fields=['priority'], name='course_cour_priorit_dedac7_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='courselesson', |
|||
index=models.Index(fields=['is_active'], name='course_cour_is_acti_490c61_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='courselesson', |
|||
index=models.Index(fields=['course', 'priority'], name='course_cour_course__192d2c_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='courselesson', |
|||
index=models.Index(fields=['course', 'is_active'], name='course_cour_course__7c6f06_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='lesson', |
|||
index=models.Index(fields=['content_type'], name='course_less_content_e1cf57_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='lesson', |
|||
index=models.Index(fields=['created_at'], name='course_less_created_4efb58_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='lessoncompletion', |
|||
index=models.Index(fields=['student'], name='course_less_student_f3c9b8_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='lessoncompletion', |
|||
index=models.Index(fields=['course_lesson'], name='course_less_course__1f3841_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='lessoncompletion', |
|||
index=models.Index(fields=['completed_at'], name='course_less_complet_8d2220_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='lessoncompletion', |
|||
index=models.Index(fields=['student', 'course_lesson'], name='course_less_student_3b6367_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='participant', |
|||
index=models.Index(fields=['student'], name='course_part_student_566b08_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='participant', |
|||
index=models.Index(fields=['course'], name='course_part_course__7cbf7c_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='participant', |
|||
index=models.Index(fields=['joined_date'], name='course_part_joined__27eaa0_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='participant', |
|||
index=models.Index(fields=['student', 'course'], name='course_part_student_c97a97_idx'), |
|||
), |
|||
] |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue