Add performance optimizations and database indexes
Database Indexes (migrations 006-009): - Add case-insensitive indexes for auth lookups (email, username) - Add composite indexes for task kanban queries - Add indexes for notification, document, and completion queries - Add unique index for active share codes - Remove redundant idx_share_code_active and idx_notification_user_sent Repository Optimizations: - Add FindResidenceIDsByUser() lightweight method (IDs only, no preloads) - Optimize GetResidenceUsers() with single UNION query (was 2 queries) - Optimize kanban completion preloads to minimal columns (id, task_id, completed_at) Service Optimizations: - Remove Category/Priority/Frequency preloads from task queries - Remove summary calculations from CRUD responses (client calculates) - Use lightweight FindResidenceIDsByUser() instead of full FindByUser() These changes reduce database load and response times for common operations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
23
migrations/006_performance_indexes.down.sql
Normal file
23
migrations/006_performance_indexes.down.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
-- Rollback performance optimization indexes
|
||||
-- Migration: 006_performance_indexes
|
||||
|
||||
DROP INDEX IF EXISTS idx_user_email_lower;
|
||||
DROP INDEX IF EXISTS idx_user_username_lower;
|
||||
DROP INDEX IF EXISTS idx_admin_email_lower;
|
||||
|
||||
DROP INDEX IF EXISTS idx_task_residence_status;
|
||||
DROP INDEX IF EXISTS idx_task_residence_active;
|
||||
DROP INDEX IF EXISTS idx_task_next_due_date;
|
||||
|
||||
DROP INDEX IF EXISTS idx_notification_user_read;
|
||||
DROP INDEX IF EXISTS idx_notification_user_sent;
|
||||
DROP INDEX IF EXISTS idx_notification_task;
|
||||
|
||||
DROP INDEX IF EXISTS idx_document_residence_active_type;
|
||||
DROP INDEX IF EXISTS idx_document_expiry_active;
|
||||
|
||||
DROP INDEX IF EXISTS idx_contractor_created_by;
|
||||
DROP INDEX IF EXISTS idx_completion_task;
|
||||
DROP INDEX IF EXISTS idx_completion_completed_by;
|
||||
DROP INDEX IF EXISTS idx_residence_member_user;
|
||||
DROP INDEX IF EXISTS idx_share_code_active;
|
||||
75
migrations/006_performance_indexes.up.sql
Normal file
75
migrations/006_performance_indexes.up.sql
Normal file
@@ -0,0 +1,75 @@
|
||||
-- Performance optimization indexes
|
||||
-- Migration: 006_performance_indexes
|
||||
|
||||
-- =====================================================
|
||||
-- CRITICAL: Case-insensitive indexes for auth lookups
|
||||
-- =====================================================
|
||||
-- These eliminate full table scans on login/registration
|
||||
CREATE INDEX IF NOT EXISTS idx_user_email_lower ON auth_user (LOWER(email));
|
||||
CREATE INDEX IF NOT EXISTS idx_user_username_lower ON auth_user (LOWER(username));
|
||||
CREATE INDEX IF NOT EXISTS idx_admin_email_lower ON admin_users (LOWER(email));
|
||||
|
||||
-- =====================================================
|
||||
-- HIGH PRIORITY: Composite indexes for common queries
|
||||
-- =====================================================
|
||||
|
||||
-- Tasks: Most common query pattern is by residence with status filters
|
||||
CREATE INDEX IF NOT EXISTS idx_task_residence_status
|
||||
ON task_task (residence_id, is_cancelled, is_archived);
|
||||
|
||||
-- Tasks: For kanban board queries (active tasks by residence)
|
||||
CREATE INDEX IF NOT EXISTS idx_task_residence_active
|
||||
ON task_task (residence_id, is_archived, in_progress)
|
||||
WHERE is_cancelled = false;
|
||||
|
||||
-- Tasks: For overdue queries (next_due_date lookups)
|
||||
CREATE INDEX IF NOT EXISTS idx_task_next_due_date
|
||||
ON task_task (next_due_date)
|
||||
WHERE is_cancelled = false AND is_archived = false AND next_due_date IS NOT NULL;
|
||||
|
||||
-- Notifications: Queried constantly for unread count
|
||||
CREATE INDEX IF NOT EXISTS idx_notification_user_read
|
||||
ON notifications_notification (user_id, read);
|
||||
|
||||
-- Notifications: For pending notification worker
|
||||
CREATE INDEX IF NOT EXISTS idx_notification_user_sent
|
||||
ON notifications_notification (user_id, sent);
|
||||
|
||||
-- Notifications: Task-based lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_notification_task
|
||||
ON notifications_notification (task_id)
|
||||
WHERE task_id IS NOT NULL;
|
||||
|
||||
-- Documents: Warranty expiry queries
|
||||
CREATE INDEX IF NOT EXISTS idx_document_residence_active_type
|
||||
ON task_document (residence_id, is_active, document_type);
|
||||
|
||||
-- Documents: Expiring warranties lookup
|
||||
CREATE INDEX IF NOT EXISTS idx_document_expiry_active
|
||||
ON task_document (expiry_date, is_active)
|
||||
WHERE document_type = 'warranty' AND is_active = true;
|
||||
|
||||
-- =====================================================
|
||||
-- MEDIUM PRIORITY: Foreign key indexes
|
||||
-- =====================================================
|
||||
|
||||
-- Contractor: Query by creator (user's personal contractors)
|
||||
CREATE INDEX IF NOT EXISTS idx_contractor_created_by
|
||||
ON task_contractor (created_by_id);
|
||||
|
||||
-- Task completions: Query by task
|
||||
CREATE INDEX IF NOT EXISTS idx_completion_task
|
||||
ON task_taskcompletion (task_id);
|
||||
|
||||
-- Task completions: Query by user who completed
|
||||
CREATE INDEX IF NOT EXISTS idx_completion_completed_by
|
||||
ON task_taskcompletion (completed_by_id);
|
||||
|
||||
-- Residence members: Query by user
|
||||
CREATE INDEX IF NOT EXISTS idx_residence_member_user
|
||||
ON residence_residencemember (user_id);
|
||||
|
||||
-- Share codes: Active code lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_share_code_active
|
||||
ON residence_residencesharecode (code, is_active)
|
||||
WHERE is_active = true;
|
||||
5
migrations/007_custom_interval_days.down.sql
Normal file
5
migrations/007_custom_interval_days.down.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- Rollback custom_interval_days column
|
||||
-- Migration: 007_custom_interval_days
|
||||
|
||||
ALTER TABLE task_task
|
||||
DROP COLUMN IF EXISTS custom_interval_days;
|
||||
8
migrations/007_custom_interval_days.up.sql
Normal file
8
migrations/007_custom_interval_days.up.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- Add custom_interval_days for custom frequency tasks
|
||||
-- Migration: 007_custom_interval_days
|
||||
|
||||
ALTER TABLE task_task
|
||||
ADD COLUMN IF NOT EXISTS custom_interval_days INTEGER;
|
||||
|
||||
-- Add comment for documentation
|
||||
COMMENT ON COLUMN task_task.custom_interval_days IS 'For Custom frequency tasks, the user-specified number of days between occurrences';
|
||||
8
migrations/008_additional_performance_indexes.down.sql
Normal file
8
migrations/008_additional_performance_indexes.down.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- Rollback additional performance optimization indexes
|
||||
-- Migration: 008_additional_performance_indexes
|
||||
|
||||
DROP INDEX IF EXISTS idx_task_kanban_composite;
|
||||
DROP INDEX IF EXISTS idx_completion_task_date;
|
||||
DROP INDEX IF EXISTS idx_sharecode_code_active;
|
||||
DROP INDEX IF EXISTS idx_residence_users_user_residence;
|
||||
DROP INDEX IF EXISTS idx_task_in_progress;
|
||||
47
migrations/008_additional_performance_indexes.up.sql
Normal file
47
migrations/008_additional_performance_indexes.up.sql
Normal file
@@ -0,0 +1,47 @@
|
||||
-- Additional performance optimization indexes
|
||||
-- Migration: 008_additional_performance_indexes
|
||||
|
||||
-- =====================================================
|
||||
-- KANBAN QUERY OPTIMIZATION
|
||||
-- =====================================================
|
||||
|
||||
-- Composite index for kanban board queries
|
||||
-- Covers: WHERE residence_id IN ? AND is_archived = false
|
||||
-- with ordering by due_date, next_due_date
|
||||
CREATE INDEX IF NOT EXISTS idx_task_kanban_composite
|
||||
ON task_task (residence_id, is_archived, is_cancelled, next_due_date, due_date)
|
||||
WHERE is_archived = false;
|
||||
|
||||
-- =====================================================
|
||||
-- COMPLETION QUERY OPTIMIZATION
|
||||
-- =====================================================
|
||||
|
||||
-- Ordering index for completion queries (most recent first)
|
||||
CREATE INDEX IF NOT EXISTS idx_completion_task_date
|
||||
ON task_taskcompletion (task_id, completed_at DESC);
|
||||
|
||||
-- =====================================================
|
||||
-- SHARE CODE OPTIMIZATION
|
||||
-- =====================================================
|
||||
|
||||
-- Unique index for active share code lookups
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_sharecode_code_active
|
||||
ON residence_residencesharecode (code)
|
||||
WHERE is_active = true;
|
||||
|
||||
-- =====================================================
|
||||
-- RESIDENCE USER ACCESS OPTIMIZATION
|
||||
-- =====================================================
|
||||
|
||||
-- Index for residence user membership queries (used by FindResidenceIDsByUser)
|
||||
CREATE INDEX IF NOT EXISTS idx_residence_users_user_residence
|
||||
ON residence_residence_users (user_id, residence_id);
|
||||
|
||||
-- =====================================================
|
||||
-- TASK IN_PROGRESS QUERIES
|
||||
-- =====================================================
|
||||
|
||||
-- Index for in_progress task queries (kanban "In Progress" column)
|
||||
CREATE INDEX IF NOT EXISTS idx_task_in_progress
|
||||
ON task_task (residence_id, in_progress)
|
||||
WHERE in_progress = true AND is_cancelled = false AND is_archived = false;
|
||||
10
migrations/009_remove_redundant_indexes.down.sql
Normal file
10
migrations/009_remove_redundant_indexes.down.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Rollback: Recreate removed indexes
|
||||
|
||||
-- Recreate share code index (from migration 006)
|
||||
CREATE INDEX IF NOT EXISTS idx_share_code_active
|
||||
ON residence_residencesharecode (residence_id)
|
||||
WHERE is_active = true;
|
||||
|
||||
-- Recreate notification user+sent index (from migration 006)
|
||||
CREATE INDEX IF NOT EXISTS idx_notification_user_sent
|
||||
ON notifications_notification (user_id, sent);
|
||||
15
migrations/009_remove_redundant_indexes.up.sql
Normal file
15
migrations/009_remove_redundant_indexes.up.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Migration: 009_remove_redundant_indexes
|
||||
-- Description: Remove indexes that are redundant or unused
|
||||
|
||||
-- Remove redundant share code index
|
||||
-- idx_share_code_active is superseded by unique idx_sharecode_code_active (migration 008)
|
||||
-- Both filter WHERE is_active = true, but 008's unique index on (code) is more restrictive
|
||||
DROP INDEX IF EXISTS idx_share_code_active;
|
||||
|
||||
-- Remove unused composite notification index
|
||||
-- idx_notification_user_sent on (user_id, sent) is never used:
|
||||
-- - GetPendingNotifications() only filters on sent, not user_id
|
||||
-- - FindByUser() only filters on user_id, not sent (uses idx_notification_user_created_at)
|
||||
-- - No queries combine user_id AND sent together
|
||||
-- The leading column (user_id) queries already use idx_notification_user_created_at
|
||||
DROP INDEX IF EXISTS idx_notification_user_sent;
|
||||
Reference in New Issue
Block a user