feat(ddl): Add FK indexes for 32 missing foreign keys

Creates 99-additional-fk-indexes.sql with indexes for all FKs
that were identified without dedicated index coverage.

Organized by priority:
- HIGH: billing (3), notifications (1), sales (2), commissions (1)
- MEDIUM: audit (2), storage (1), webhooks (1), whatsapp (1)
- LOW: created_by/approved_by fields across multiple schemas

References: TASK-2026-02-03-REMEDIACION-BD (P1)
Based on: INFORME-INTEGRIDAD-REFERENCIAL.md analysis

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Adrian Flores Cortes 2026-02-03 17:18:51 -06:00
parent c1c5892364
commit fa67494ec7

View File

@ -0,0 +1,220 @@
-- =============================================================================
-- INDICES ADICIONALES PARA FOREIGN KEYS
-- Proyecto: template-saas
-- Generado por: TASK-2026-02-03-REMEDIACION-BD (P1)
-- Fecha: 2026-02-03
-- Descripcion: Indices para las 32 FKs que carecian de indice dedicado
-- Referencia: orchestration/tareas/TASK-2026-02-03-VALIDACION-INTEGRAL-MODELADO-BD/
-- entregables/INFORME-INTEGRIDAD-REFERENCIAL.md
-- =============================================================================
-- =============================================================================
-- PRIORIDAD ALTA: Tablas frecuentemente consultadas
-- =============================================================================
-- -----------------------------------------------------------------------------
-- Schema: billing
-- -----------------------------------------------------------------------------
-- FK: billing.subscriptions.plan_id -> plans.plans(id)
CREATE INDEX IF NOT EXISTS idx_subscriptions_plan
ON billing.subscriptions(plan_id);
-- FK: billing.invoices.subscription_id -> billing.subscriptions(id)
CREATE INDEX IF NOT EXISTS idx_invoices_subscription
ON billing.invoices(subscription_id) WHERE subscription_id IS NOT NULL;
-- FK: billing.payments.invoice_id -> billing.invoices(id)
CREATE INDEX IF NOT EXISTS idx_payments_invoice
ON billing.payments(invoice_id) WHERE invoice_id IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: notifications
-- -----------------------------------------------------------------------------
-- FK: notifications.notifications.template_id -> notifications.templates(id)
CREATE INDEX IF NOT EXISTS idx_notifications_template
ON notifications.notifications(template_id) WHERE template_id IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: sales
-- -----------------------------------------------------------------------------
-- FK: sales.leads.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_leads_created_by
ON sales.leads(created_by) WHERE created_by IS NOT NULL;
-- FK: sales.opportunities.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_opportunities_created_by
ON sales.opportunities(created_by) WHERE created_by IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: commissions
-- -----------------------------------------------------------------------------
-- FK: commissions.entries.assignment_id -> commissions.assignments(id)
CREATE INDEX IF NOT EXISTS idx_entries_assignment
ON commissions.entries(assignment_id) WHERE assignment_id IS NOT NULL;
-- =============================================================================
-- PRIORIDAD MEDIA: Tablas de auditoria/historial
-- =============================================================================
-- -----------------------------------------------------------------------------
-- Schema: audit
-- -----------------------------------------------------------------------------
-- FK: audit.audit_logs.user_id -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_audit_logs_user
ON audit.audit_logs(user_id) WHERE user_id IS NOT NULL;
-- FK: audit.data_changes.user_id -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_data_changes_user
ON audit.data_changes(user_id) WHERE user_id IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: storage
-- -----------------------------------------------------------------------------
-- FK: storage.files.uploaded_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_files_uploaded_by
ON storage.files(uploaded_by) WHERE uploaded_by IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: webhooks
-- -----------------------------------------------------------------------------
-- FK: webhooks.webhooks.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_webhooks_created_by
ON webhooks.webhooks(created_by) WHERE created_by IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: whatsapp
-- -----------------------------------------------------------------------------
-- FK: whatsapp.messages.user_id -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_messages_user
ON whatsapp.messages(user_id) WHERE user_id IS NOT NULL;
-- =============================================================================
-- PRIORIDAD BAJA: Campos de auditoria (created_by/approved_by/closed_by/etc)
-- =============================================================================
-- -----------------------------------------------------------------------------
-- Schema: sales
-- -----------------------------------------------------------------------------
-- FK: sales.activities.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_activities_created_by
ON sales.activities(created_by) WHERE created_by IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: portfolio
-- -----------------------------------------------------------------------------
-- FK: portfolio.categories.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_categories_created_by
ON portfolio.categories(created_by) WHERE created_by IS NOT NULL;
-- FK: portfolio.products.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_products_created_by
ON portfolio.products(created_by) WHERE created_by IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: commissions
-- -----------------------------------------------------------------------------
-- FK: commissions.schemes.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_schemes_created_by
ON commissions.schemes(created_by) WHERE created_by IS NOT NULL;
-- FK: commissions.assignments.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_assignments_created_by
ON commissions.assignments(created_by) WHERE created_by IS NOT NULL;
-- FK: commissions.entries.approved_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_entries_approved_by
ON commissions.entries(approved_by) WHERE approved_by IS NOT NULL;
-- FK: commissions.periods.closed_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_periods_closed_by
ON commissions.periods(closed_by) WHERE closed_by IS NOT NULL;
-- FK: commissions.periods.paid_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_periods_paid_by
ON commissions.periods(paid_by) WHERE paid_by IS NOT NULL;
-- FK: commissions.periods.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_periods_created_by
ON commissions.periods(created_by) WHERE created_by IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: mlm
-- -----------------------------------------------------------------------------
-- FK: mlm.structures.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_structures_created_by
ON mlm.structures(created_by) WHERE created_by IS NOT NULL;
-- FK: mlm.nodes.highest_rank_id -> mlm.ranks(id)
CREATE INDEX IF NOT EXISTS idx_nodes_highest_rank
ON mlm.nodes(highest_rank_id) WHERE highest_rank_id IS NOT NULL;
-- FK: mlm.rank_history.previous_rank_id -> mlm.ranks(id)
CREATE INDEX IF NOT EXISTS idx_rank_history_previous_rank
ON mlm.rank_history(previous_rank_id) WHERE previous_rank_id IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: users
-- -----------------------------------------------------------------------------
-- FK: users.roles.parent_role_id -> users.roles(id)
CREATE INDEX IF NOT EXISTS idx_roles_parent_role
ON users.roles(parent_role_id) WHERE parent_role_id IS NOT NULL;
-- FK: users.invitations.role_id -> users.roles(id)
CREATE INDEX IF NOT EXISTS idx_invitations_role
ON users.invitations(role_id) WHERE role_id IS NOT NULL;
-- FK: users.invitations.accepted_by_user_id -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_invitations_accepted_by
ON users.invitations(accepted_by_user_id) WHERE accepted_by_user_id IS NOT NULL;
-- FK: users.invitations.created_by -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_invitations_created_by
ON users.invitations(created_by) WHERE created_by IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: auth
-- -----------------------------------------------------------------------------
-- FK: auth.refresh_tokens.session_id -> auth.sessions(id)
CREATE INDEX IF NOT EXISTS idx_refresh_tokens_session
ON auth.refresh_tokens(session_id) WHERE session_id IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: notifications
-- -----------------------------------------------------------------------------
-- FK: notifications.delivery_logs.queue_id -> notifications.notification_queue(id)
CREATE INDEX IF NOT EXISTS idx_delivery_logs_queue
ON notifications.delivery_logs(queue_id) WHERE queue_id IS NOT NULL;
-- FK: notifications.delivery_logs.device_id -> notifications.user_devices(id)
CREATE INDEX IF NOT EXISTS idx_delivery_logs_device
ON notifications.delivery_logs(device_id) WHERE device_id IS NOT NULL;
-- -----------------------------------------------------------------------------
-- Schema: feature_flags
-- -----------------------------------------------------------------------------
-- FK: feature_flags.flag_evaluations.user_id -> users.users(id)
CREATE INDEX IF NOT EXISTS idx_flag_evaluations_user
ON feature_flags.flag_evaluations(user_id) WHERE user_id IS NOT NULL;
-- =============================================================================
-- FIN DE INDICES ADICIONALES PARA FOREIGN KEYS
-- Total: 32 indices creados
-- Nota: El informe original indicaba 31 FKs sin indice (21.7%), pero el
-- analisis detallado revela 32 FKs. Todos han sido cubiertos.
-- =============================================================================