Sicherheit zuerst: Parameter statt Strings
Nicht so
cur.execute(
f"SELECT * FROM users WHERE email = '{email}'"
)
# email = "' OR '1'='1" → alle UserSo
cur.execute(
"SELECT id, name FROM users WHERE email = %s",
(email,),
)Die wichtigsten Regeln
Kein SELECT *
Spalten explizit nennen: weniger Daten, stabil bei Schemaänderungen, Index-only-Scans möglich.
Gezielt indizieren
Indizes auf Fremdschlüssel und Spalten in WHERE/JOIN/ORDER BY. Mit EXPLAIN prüfen, ob sie greifen.
Constraints in der DB
NOT NULL, UNIQUE, FOREIGN KEY, CHECK – die Datenbank erzwingt Regeln auch dann, wenn der Code einen Bug hat.
Transaktionen
Zusammengehörige Änderungen in BEGIN … COMMIT, damit nie nur die Hälfte gespeichert wird.
Versionierte Migrationen
Jede Schemaänderung als Skript im Repo (Alembic, Flyway, EF Migrations) – reproduzierbar in jeder Umgebung.
Konsistente Namen
snake_case, eindeutige Konvention für Tabellen (Singular oder Plural) und Fremdschlüssel wie user_id.
Lesbare Joins
Nicht so
SELECT * FROM orders o, users u
WHERE o.user_id = u.id AND u.country = 'DE'So
SELECT o.id, o.total, u.name
FROM orders AS o
JOIN users AS u ON u.id = o.user_id
WHERE u.country = 'DE';