Files
leocrm/alembic/versions/0099_add_created_at_indexes.py
T

150 lines
3.5 KiB
Python
Raw Normal View History

"""Add created_at indexes for performance on large tables.
Order by created_at DESC is the slowest query at 68ms with 100k rows.
This migration adds indexes on created_at for all tenant-scoped tables
that are commonly sorted by created_at.
Revision ID: 0099
Revises: 0098
"""
from __future__ import annotations
from alembic import op
revision = "0099"
down_revision = "0098"
branch_labels = None
depends_on = None
# Tables that are commonly sorted by created_at DESC
TABLES = [
"contacts",
"audit_log",
"calendar_entries",
"comm_messages",
"files",
"mails",
"tasks",
"automation_runs",
"ai_chat_messages",
"ai_chat_sessions",
"entity_history",
"notifications",
"event_outbox",
"outbox_deliveries",
"entity_attachments",
"contact_merge_history",
"webhooks",
"tags",
"contact_folder_permissions",
"entity_permissions",
"entity_policies",
"guest_users",
"guest_invitations",
"user_groups",
"saved_filters",
"saved_views",
"workspaces",
"workspace_modules",
"workspace_users",
"workspace_widgets",
"api_tokens",
"sessions",
"password_reset_tokens",
"custom_field_definitions",
"system_settings",
"plugin_migrations",
"tenant_plugin_activation",
"plugin_allowlist",
"permissions",
"permission_templates",
"permission_delegations",
"currencies",
"tax_rates",
"sequences",
"addresses",
"bank_accounts",
"contactpersons",
"contact_folders",
"user_preferences",
"deletion_log",
"backups",
"consumer_inbox",
"folders",
"calendars",
"calendar_entry_links",
"calendar_shares",
"user_calendar_visibility",
"subtasks",
"resources",
"resource_bookings",
"entity_links",
"forgejo_reported_errors",
"comm_conversations",
"comm_participants",
"comm_message_blocks",
"comm_message_attachments",
"comm_message_reactions",
"comm_message_reads",
"comm_conversation_pins",
"comm_conversation_mutes",
"mail_accounts",
"mail_folders",
"mail_labels",
"mail_label_assignments",
"mail_attachments",
"mail_signatures",
"mail_templates",
"mail_rules",
"mail_sync_queue",
"mail_seen_by",
"mail_account_delegates",
"mail_account_send_permissions",
"pgp_keys",
"contact_pgp_keys",
"ai_providers",
"ai_models",
"ai_presets",
"ai_agents",
"ai_chat_folders",
"ai_chat_attachments",
"ai_proactive_suggestions",
"ai_proactive_context_log",
"ai_proactive_settings",
"automation_agent_definitions",
"automation_agent_versions",
"automation_definitions",
"automation_versions",
"automation_cron_jobs",
"automation_agent_runs",
"unified_search_index_log",
"unified_search_providers",
"report_templates",
"report_instances",
"mcp_server_configs",
"share_links",
"tag_assignments",
"plugin_test_data",
"vacation_sent_log",
]
def upgrade() -> None:
# Add created_at index only if the column exists
for table in TABLES:
op.execute(
"DO $do$ BEGIN "
"IF EXISTS (SELECT 1 FROM information_schema.columns "
f"WHERE table_name = '{table}' AND column_name = 'created_at') THEN "
f"CREATE INDEX IF NOT EXISTS ix_{table}_created_at "
f"ON {table} (created_at DESC); "
"END IF; "
"END $do$;"
)
def downgrade() -> None:
for table in TABLES:
op.execute(f"DROP INDEX IF EXISTS ix_{table}_created_at")