perf(db): 80 fehlende Indizes auf Fremdschlüssel-Spalten ergänzt
Postgres legt für FK-Spalten selbst KEINEN Index an (nur für die referenzierte PK-Seite) - grep über alle Models ergab 0 explizite Indizes im gesamten Schema trotz 86 Fremdschlüsseln. Ohne Index braucht jede Lookup-Query von der "viele"-Seite (z.B. "alle Fehlbestände zu diesem Objekt", "alle Kontrollen zu diesem Benutzer") einen Sequential Scan - bei aktueller Datenmenge unauffällig, würde mit wachsendem Bestand aber zum Problem. 5 Spalten ausgelassen, weil bereits über eine UniqueConstraint als führende Spalte indiziert (Postgres nutzt den führenden Teil eines zusammengesetzten Unique-Index für Einzelspalten-Lookups genauso): objektposition.objekt_id, bestand.lagerplatz_id, beladungsvorlage. objekttyp_id, vorlagenposition.vorlage_id, benutzer_qualifikation. benutzer_id. dokument.vorgaenger_id hatte bereits einen Index (Migration 0027). Fund beim Abgleich gegen die database-optimization-Checkliste aus ai-coding-starter-kit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
@@ -0,0 +1,120 @@
|
|||||||
|
"""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}")
|
||||||
Reference in New Issue
Block a user