78 lines
3.5 KiB
SQL
78 lines
3.5 KiB
SQL
-- =====================================================
|
|
-- Index Optimization
|
|
--
|
|
-- Adds partial indexes for common query patterns,
|
|
-- covers the advanced search filter combinations,
|
|
-- and optimizes reporting queries.
|
|
-- =====================================================
|
|
|
|
-- 1. Active members composite index (most common query pattern)
|
|
-- Covers: listMembers, searchMembers, all reporting functions
|
|
CREATE INDEX IF NOT EXISTS ix_members_active_account_status
|
|
ON public.members(account_id, status, last_name, first_name)
|
|
WHERE is_archived = false;
|
|
|
|
-- 2. Entry date range queries (searchMembers with date filters)
|
|
CREATE INDEX IF NOT EXISTS ix_members_entry_date
|
|
ON public.members(account_id, entry_date)
|
|
WHERE entry_date IS NOT NULL;
|
|
|
|
-- 3. Dues category filter (searchMembers)
|
|
CREATE INDEX IF NOT EXISTS ix_members_dues_category
|
|
ON public.members(account_id, dues_category_id)
|
|
WHERE dues_category_id IS NOT NULL;
|
|
|
|
-- 4. Boolean flag filters (searchMembers flag queries)
|
|
-- Partial indexes only store rows where the flag is true (very compact)
|
|
CREATE INDEX IF NOT EXISTS ix_members_honorary
|
|
ON public.members(account_id) WHERE is_honorary = true;
|
|
CREATE INDEX IF NOT EXISTS ix_members_youth
|
|
ON public.members(account_id) WHERE is_youth = true;
|
|
CREATE INDEX IF NOT EXISTS ix_members_founding
|
|
ON public.members(account_id) WHERE is_founding_member = true;
|
|
CREATE INDEX IF NOT EXISTS ix_members_retiree
|
|
ON public.members(account_id) WHERE is_retiree = true;
|
|
|
|
-- 5. Active SEPA mandates lookup (finance integration)
|
|
CREATE INDEX IF NOT EXISTS ix_sepa_mandates_active_lookup
|
|
ON public.sepa_mandates(member_id, status)
|
|
WHERE status = 'active' AND is_primary = true;
|
|
|
|
-- 6. Communications per member (timeline queries)
|
|
CREATE INDEX IF NOT EXISTS ix_member_comms_member_date
|
|
ON public.member_communications(member_id, created_at DESC);
|
|
|
|
-- 7. Audit log: action-type filtering (timeline with action filter)
|
|
CREATE INDEX IF NOT EXISTS ix_member_audit_member_action
|
|
ON public.member_audit_log(member_id, action, created_at DESC);
|
|
|
|
-- 8. Tag assignments: member lookup (for search filter + detail view)
|
|
CREATE INDEX IF NOT EXISTS ix_tag_assignments_member
|
|
ON public.member_tag_assignments(member_id);
|
|
|
|
-- 9. Reporting: active members for retention/duration CROSS JOIN
|
|
-- Column order: account_id first (equality), then date columns (range scans)
|
|
-- is_archived excluded from key since it's in WHERE clause
|
|
CREATE INDEX IF NOT EXISTS ix_members_active_reporting
|
|
ON public.members(account_id, entry_date, exit_date, status)
|
|
WHERE is_archived = false;
|
|
|
|
-- 10. Member merge log: primary member lookup
|
|
CREATE INDEX IF NOT EXISTS ix_member_merges_primary
|
|
ON public.member_merges(primary_member_id);
|
|
|
|
-- 11. GDPR: candidates for anonymization (batch enforcement query)
|
|
-- status excluded from key since enforcement query uses dynamic ANY(array)
|
|
-- Covers: WHERE account_id = ? AND exit_date IS NOT NULL AND exit_date + interval <= current_date
|
|
CREATE INDEX IF NOT EXISTS ix_members_gdpr_candidates
|
|
ON public.members(account_id, exit_date)
|
|
WHERE exit_date IS NOT NULL AND is_archived = false AND first_name != 'ANONYMISIERT';
|
|
|
|
-- 12. Portal invitations: account listing (listPortalInvitations query)
|
|
CREATE INDEX IF NOT EXISTS ix_portal_invitations_account_date
|
|
ON public.member_portal_invitations(account_id, created_at DESC);
|
|
|
|
-- 13. Department assignments by department (searchMembers department filter subquery)
|
|
CREATE INDEX IF NOT EXISTS ix_dept_assignments_department
|
|
ON public.member_department_assignments(department_id, member_id);
|