-- ═══════════════════════════════════════════════════════════════ -- 007: DB Indexes Optimization (audit 2026-05-22) -- -- Adds 18 missing indexes for hot-path queries identified by -- comprehensive audit. Skips users.email — UNIQUE constraint -- already provides equality-lookup index automatically. -- -- Expected impact: 30-60% speedup for admin overview / analytics, -- 10-20% for per-user notification + session timelines, and -- prevents full-table scans on CASCADE DELETE of classroom_sessions. -- ═══════════════════════════════════════════════════════════════ -- ── users: filter/sort by created_at, last_login, role ────────── CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at); CREATE INDEX IF NOT EXISTS idx_users_last_login ON users(last_login); CREATE INDEX IF NOT EXISTS idx_users_role ON users(role); CREATE INDEX IF NOT EXISTS idx_users_banned_role ON users(is_banned, role); -- ── test_sessions: date range filters + JOIN on subject_id ────── CREATE INDEX IF NOT EXISTS idx_test_sessions_started_at ON test_sessions(started_at); CREATE INDEX IF NOT EXISTS idx_test_sessions_finished_at ON test_sessions(finished_at); CREATE INDEX IF NOT EXISTS idx_test_sessions_subject_id ON test_sessions(subject_id); CREATE INDEX IF NOT EXISTS idx_test_sessions_status_finished ON test_sessions(status, finished_at DESC); -- ── notifications: per-user timeline (was indexed on is_read, not created_at) ── CREATE INDEX IF NOT EXISTS idx_notifications_user_created ON notifications(user_id, created_at DESC); -- ── admin_audit_log: target LIKE 'user:%' + action filters ────── CREATE INDEX IF NOT EXISTS idx_audit_log_target ON admin_audit_log(target); CREATE INDEX IF NOT EXISTS idx_audit_log_action ON admin_audit_log(action); CREATE INDEX IF NOT EXISTS idx_audit_log_action_date ON admin_audit_log(action, created_at DESC); -- ── classroom_*: CASCADE DELETE safety (FKs without indexes) ──── CREATE INDEX IF NOT EXISTS idx_classroom_muted_session ON classroom_muted(session_id); CREATE INDEX IF NOT EXISTS idx_classroom_attendance_session ON classroom_attendance(session_id); CREATE INDEX IF NOT EXISTS idx_classroom_invites_session ON classroom_invites(session_id); CREATE INDEX IF NOT EXISTS idx_classroom_notes_session ON classroom_notes(session_id); CREATE INDEX IF NOT EXISTS idx_classroom_draw_permissions_session ON classroom_draw_permissions(session_id); CREATE INDEX IF NOT EXISTS idx_classroom_hands_session ON classroom_hands(session_id); CREATE INDEX IF NOT EXISTS idx_classroom_chat_session_date ON classroom_chat(session_id, created_at); -- ── submissions: per-student timeline ──────────────────────────── CREATE INDEX IF NOT EXISTS idx_submissions_student_date ON submissions(student_id, submitted_at DESC); -- ── questions.difficulty: exam builder filter ──────────────────── CREATE INDEX IF NOT EXISTS idx_questions_difficulty ON questions(difficulty);