"""Index plugin_metrics for host/dashboard reads plugin_metrics had only a PK on id, so every host-detail / full-metrics / dashboard-widget query (all filter by source_module + resource_name over a recorded_at range) sequentially scanned the whole time-series table — slower as samples accumulate. Add the two composite indexes that match those query shapes. The non-concurrent CREATE INDEX takes a brief exclusive lock; it runs once at startup migration time, acceptable for this table. Revision ID: 0023_plugin_metrics_indexes Revises: 0022_unify_monitors Create Date: 2026-06-20 """ from typing import Sequence, Union from alembic import op revision: str = "0023_plugin_metrics_indexes" down_revision: Union[str, None] = "0022_unify_monitors" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.create_index( "ix_plugin_metrics_module_resource_recorded", "plugin_metrics", ["source_module", "resource_name", "recorded_at"], ) op.create_index( "ix_plugin_metrics_module_resource_metric_recorded", "plugin_metrics", ["source_module", "resource_name", "metric_name", "recorded_at"], ) def downgrade() -> None: op.drop_index("ix_plugin_metrics_module_resource_metric_recorded", "plugin_metrics") op.drop_index("ix_plugin_metrics_module_resource_recorded", "plugin_metrics")