wiki:OtherDevelopments

Version 1 (modified by 221296, 2 hours ago) ( diff )

--

SQL Performance and Index Optimization

The goal of this phase is to analyze and improve the performance of the most important database operations in the Online Learning Platform Management System.

The application contains several frequent operations:

browsing and filtering courses checking existing enrollments validating active user subscriptions loading course modules and lessons managing support tickets generating reports for enrollments, certificates and quiz attempts

The following indexes are not automatically created by primary key constraints, but they can improve the performance of WHERE filters, JOIN operations and report queries.

Testing Methodology

The performance analysis is done using PostgreSQL EXPLAIN ANALYZE.

The testing process is:

first, the query is executed without additional indexes then, the required index is created the same query is executed again the execution plan and execution time are compared

This allows us to check whether PostgreSQL uses Seq Scan, Index Scan or another optimized query plan.

Scenario 1: Course Browsing and Filtering

Users frequently browse available courses and filter them by course status, name or price.

SQL query:

EXPLAIN ANALYZE
SELECT c.course_id, c.name, c.price, c.status
FROM course c
WHERE c.status = 'ACTIVE'
ORDER BY c.price;

Indexes:

CREATE INDEX IF NOT EXISTS idx_course_status_price
ON course(status, price);

CREATE INDEX IF NOT EXISTS idx_course_name
ON course(name);

Explanation:

The composite index on (status, price) is useful because the query filters by status and sorts by price.

The index on name improves course searching by course name.

Scenario 2: Enrollment Checking

Before a user enrolls in a course, the system checks whether the user is already enrolled in that course.

SQL query:

EXPLAIN ANALYZE
SELECT e.enrollment_id, e.user_id, e.course_id, e.completion_status
FROM enrollment e
WHERE e.user_id = 1
AND e.course_id = 3;

Index:

CREATE INDEX IF NOT EXISTS idx_enrollment_user_course
ON enrollment(user_id, course_id);

Explanation:

This index is useful because the application frequently searches enrollments by both user_id and course_id.

Without this index, PostgreSQL may scan the whole enrollment table. With the index, the lookup is faster and more direct.

Scenario 3: Active Subscription Validation

When a user wants to access course content, the system checks whether the user has an active subscription.

SQL query:

EXPLAIN ANALYZE
SELECT us.subscription_id, us.user_id, us.plan_id, us.status, us.end_date
FROM user_subscription us
WHERE us.user_id = 1
AND us.status = 'ACTIVE'
AND us.end_date >= CURRENT_DATE;

Index:

CREATE INDEX IF NOT EXISTS idx_user_subscription_active
ON user_subscription(user_id, status, end_date);

Explanation:

The index improves subscription validation because the query filters by user_id, status and end_date.

This is important because subscription validation is performed before allowing access to paid course content.

Scenario 4: Instructor Course Management

Instructors frequently manage their own courses. The system displays all courses created by a selected instructor.

SQL query:

EXPLAIN ANALYZE
SELECT c.course_id, c.name, c.price, c.status
FROM course c
WHERE c.instructor_id = 5;

Index:

CREATE INDEX IF NOT EXISTS idx_course_instructor_id
ON course(instructor_id);

Explanation:

The instructor_id column is used for filtering courses by instructor. This index improves the performance of the instructor dashboard.

Scenario 5: Course Content Loading

When a user opens a course, the application loads all modules and lessons for that course.

SQL query:

EXPLAIN ANALYZE
SELECT
m.module_id,
m.title AS module_title,
l.lesson_id,
l.title AS lesson_title
FROM module m
JOIN lesson l ON l.module_id = m.module_id
WHERE m.course_id = 3
ORDER BY m.module_id, l.lesson_id;

Indexes:

CREATE INDEX IF NOT EXISTS idx_module_course_id
ON module(course_id);

CREATE INDEX IF NOT EXISTS idx_lesson_module_id
ON lesson(module_id);

Explanation:

The index on module(course_id) improves loading modules for a selected course.

The index on lesson(module_id) improves loading lessons for each module.

Scenario 6: Admin Support Ticket Filtering

Administrators frequently filter support tickets by status and check the newest tickets first.

SQL query:

EXPLAIN ANALYZE
SELECT st.ticket_id, st.subject, st.status, st.created_at
FROM support_ticket st
WHERE st.status = 'OPEN'
ORDER BY st.created_at DESC;

Index:

CREATE INDEX IF NOT EXISTS idx_support_ticket_status_created
ON support_ticket(status, created_at DESC);

Explanation:

This index is useful because the admin panel filters tickets by status and sorts them by created_at.

Scenario 7: Annual Enrollment and Certificate Report

This report analyzes enrollments, completed courses and issued certificates per year.

SQL query:

EXPLAIN ANALYZE
SELECT
EXTRACT(YEAR FROM e.enroll_date) AS year,
COUNT(DISTINCT e.enrollment_id) AS total_enrollments,
COUNT(DISTINCT CASE
WHEN e.completion_status = 'COMPLETED' THEN e.enrollment_id
END) AS completed_enrollments,
COUNT(DISTINCT c.certificate_id) AS issued_certificates,
AVG(e.progress_percentage) AS average_progress
FROM enrollment e
LEFT JOIN certificate c ON c.enrollment_id = e.enrollment_id
GROUP BY EXTRACT(YEAR FROM e.enroll_date)
ORDER BY year;

Indexes:

CREATE INDEX IF NOT EXISTS idx_enrollment_enroll_date
ON enrollment(enroll_date);

CREATE INDEX IF NOT EXISTS idx_enrollment_completion_status
ON enrollment(completion_status);

CREATE INDEX IF NOT EXISTS idx_certificate_enrollment_id
ON certificate(enrollment_id);

Explanation:

The index on enroll_date improves time-based reports.

The index on completion_status helps when filtering completed enrollments.

The index on certificate(enrollment_id) improves the join between certificate and enrollment.

Scenario 8: Quiz Attempts Report

The system can analyze quiz attempts by user, quiz and attempt date.

SQL query:

EXPLAIN ANALYZE
SELECT
qa.user_id,
qa.quiz_id,
COUNT(*) AS total_attempts,
AVG(qa.score) AS average_score
FROM quiz_attempt qa
GROUP BY qa.user_id, qa.quiz_id
ORDER BY qa.user_id;

Indexes:

CREATE INDEX IF NOT EXISTS idx_quiz_attempt_user_id
ON quiz_attempt(user_id);

CREATE INDEX IF NOT EXISTS idx_quiz_attempt_quiz_id
ON quiz_attempt(quiz_id);

CREATE INDEX IF NOT EXISTS idx_quiz_attempt_date
ON quiz_attempt(attempt_date);

Explanation:

These indexes improve reports that analyze quiz attempts by user, quiz or date.

Note: See TracWiki for help on using the wiki.