perf(db): +21 indexes for hot-path queries (audit 2026-05-22)
Adds missing indexes identified by comprehensive audit:
users: created_at, last_login, role, (is_banned, role)
test_sessions: started_at, finished_at, subject_id, (status, finished_at DESC)
notifications: (user_id, created_at DESC) — previous idx was on is_read, not date
admin_audit_log: target, action, (action, created_at DESC)
classroom_*: session_id FK indexes — prevents full-table scan on CASCADE
DELETE (muted, attendance, invites, notes, draw_permissions, hands)
+ chat (session_id, created_at)
submissions: (student_id, submitted_at DESC) — gradebook timeline
questions: difficulty — exam builder filter
Skipped users.email — UNIQUE constraint already provides equality lookup.
Expected impact: 30-60% on admin overview / analytics, 10-20% on
notification/session timelines. CASCADE DELETE of classroom_sessions
no longer triggers full-table scans on 6 child tables.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
-- ═══════════════════════════════════════════════════════════════
|
||||
-- 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);
|
||||
Reference in New Issue
Block a user