Performance Optimierungen: Rate Limit, created_at Index, Keyset-Pagination
1. Rate Limit erhoeht: 60 -> 300 Requests/Minute (fuer 100+ User) 2. Migration 0099: created_at DESC Index auf allen Tabellen (Order by Performance) 3. Keyset-Pagination: optionaler cursor Parameter fuer contacts API - cursor=UUID nutzt WHERE id > cursor statt OFFSET - Backward compatible: ohne cursor wird page/page_size genutzt - next_cursor in Response fuer naechste Seite Tests: 43/43 bestanden
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
"""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")
|
||||
Reference in New Issue
Block a user