"""Fehlende Indizes auf Fremdschlüssel-Spalten (Postgres legt für FK-Spalten selbst KEINEN Index an, nur für die referenzierte PK-Seite - ohne expliziten Index braucht jede Lookup-Query von der "viele"-Seite (z.B. "alle Positionen zu diesem Objekt", "alle Fehlbestände zu diesem Material") einen Sequential Scan). Gefunden beim Abgleich gegen ai-coding-starter-kit-Checkliste (docs/production/database-optimization.md) - 0 explizite Indizes im gesamten Modellbestand. Spalten, die bereits über eine UniqueConstraint als führende Spalte indiziert sind, werden hier bewusst ausgelassen (Postgres nutzt den führenden Teil eines zusammengesetzten Unique-Index genauso für Einzelspalten-Lookups): objektposition.objekt_id, bestand.lagerplatz_id, beladungsvorlage.objekttyp_id, vorlagenposition.vorlage_id, benutzer_qualifikation.benutzer_id. dokument.vorgaenger_id hat bereits einen Index aus Migration 0027. Revision ID: 0028_fk_indizes Revises: 0027_dokument_versionierung Create Date: 2026-09-08 """ from typing import Sequence, Union from alembic import op revision: str = "0028_fk_indizes" down_revision: Union[str, None] = "0027_dokument_versionierung" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None _INDIZES = [ ("ausgabe", "material_id"), ("ausgabe", "geraet_instanz_id"), ("ausgabe", "empfaenger_id"), ("ausgabe", "ausgegeben_von"), ("benutzer", "einheit_id"), ("benutzer_rolle", "benutzer_id"), ("dokument", "hochgeladen_von"), ("fahrzeugdetails", "objekt_id"), ("fehlbestand", "erzeugt_von_server_id"), ("fehlbestand", "objekt_id"), ("fehlbestand", "material_id"), ("fehlbestand", "standort_id"), ("fehlbestand", "festgestellt_von"), ("fehlbestand", "kontrolle_id"), ("fehlbestand", "verantwortlicher_id"), ("geraet_instanz", "objektposition_id"), ("historie", "erzeugt_von_server_id"), ("historie", "benutzer_id"), ("kontrolle", "erzeugt_von_server_id"), ("kontrolle", "objekt_id"), ("kontrolle", "benutzer_id"), ("kontrollposition", "kontrolle_id"), ("kontrollposition", "material_id"), ("lagerort", "parent_id"), ("lagerplatz", "lagerort_id"), ("bestand", "material_id"), ("materialbewegung", "material_id"), ("materialbewegung", "von_lagerplatz_id"), ("materialbewegung", "nach_lagerplatz_id"), ("materialbewegung", "benutzer_id"), ("lagerbewegung", "objekt_id"), ("lagerbewegung", "von_standort_id"), ("lagerbewegung", "nach_standort_id"), ("lagerbewegung", "benutzer_id"), ("mangel", "objekt_id"), ("mangel", "gemeldet_von"), ("mangel", "erledigt_von"), ("mindermengen_genehmigung", "fehlbestand_id"), ("mindermengen_genehmigung", "genehmigt_von"), ("mindermengen_genehmigung", "ausloesende_kontrolle_id"), ("mindermengen_genehmigung", "beendende_kontrolle_id"), ("nachfuellung", "fehlbestand_id"), ("nachfuellung", "objekt_id"), ("nachfuellung", "material_id"), ("nachfuellung", "benutzer_id"), ("objekt", "objekttyp_id"), ("objekt", "vorlage_id"), ("objekt", "standort_id"), ("objekt", "zustaendiger_server_id"), ("objekt", "fahrzeug_id"), ("objekt", "einheit_id"), ("objektposition", "material_id"), ("rolle_berechtigung", "rolle_id"), ("rolle_berechtigung", "berechtigung_id"), ("benutzer_rolle_zuordnung", "benutzer_id"), ("benutzer_rolle_zuordnung", "rolle_id"), ("einheit", "uebergeordnete_einheit_id"), ("einheit", "standort_id"), ("benutzer_qualifikation", "qualifikationstyp_id"), ("objekttyp_qualifikationsanforderung", "objekttyp_id"), ("objekttyp_qualifikationsanforderung", "qualifikationstyp_id"), ("kategorie", "bereich_id"), ("kategorie", "ueberkategorie_id"), ("objekttyp", "bereich_id"), ("objekttyp", "kategorie_id"), ("fach", "objekttyp_id"), ("material", "kategorie_id"), ("vorlagenposition", "material_id"), ("wartungsplan", "objekttyp_id"), ("wartungsplan_position", "wartungsplan_id"), ("wartungsintervall", "wartungsplan_position_id"), ("wartungsauftrag", "objekt_id"), ("wartungsauftrag", "geraet_instanz_id"), ("wartungsauftrag", "wartungsplan_position_id"), ("wartungsauftrag", "durchgefuehrt_von"), ("zustaendigkeit", "benutzer_id"), ("zustaendigkeit", "standort_id"), ("zustaendigkeit", "objekt_id"), ("kontrollverantwortung", "objekt_id"), ("kontrollverantwortung", "benutzer_id"), ] def upgrade() -> None: for tabelle, spalte in _INDIZES: op.execute(f"CREATE INDEX IF NOT EXISTS ix_{tabelle}_{spalte} ON {tabelle} ({spalte})") def downgrade() -> None: for tabelle, spalte in _INDIZES: op.execute(f"DROP INDEX IF EXISTS ix_{tabelle}_{spalte}")