Thema: databases
-
Transaktionsgrenzen sichtbar halten
Dokumentieren, welche Zustandsänderungen gemeinsam committet werden und was zwischen Datenbanktransaktionen und externen Aufrufen passieren kann.
-
Volltextsuche in PostgreSQL mit tsvector
PostgreSQL wandelt Text mithilfe einer Sprachkonfiguration in einen tsvector aus normalisierten Lexemen um, gleicht ihn mit tsquery ab, bewertet mit ts_rank und indexiert mit GIN; Stemming und Stoppwörter werden dabei beherrscht, Tippfehler und Synonyme aber nicht von Haus aus.
-
Event Sourcing und CQRS: was sie bringen und was sie kosten
Event Sourcing speichert jede Zustandsänderung als unveränderliches Ereignis und leitet den aktuellen Zustand durch Replay ab; CQRS trennt das Schreibmodell von den Lesemodellen. Beide bringen Nachvollziehbarkeit und Flexibilität auf Kosten von Komplexität und schliesslicher Konsistenz.
-
PostgreSQL-Erweiterungen verwalten: installieren, versionieren, aktualisieren und dumpen
Eine Erweiterung bündelt SQL-Objekte und oft eine Shared Library unter einem Namen mit einer Control-Datei und versionierten Skripten; CREATE EXTENSION installiert sie je Datenbank, ALTER EXTENSION UPDATE wendet die Update-Skripte des Autors an, und pg_dump gibt nur die Zeile CREATE EXTENSION aus. Installierte Dateien, Katalogversion und geladene Bibliothek im Gleichschritt halten, besonders bei Paket-Upgrades und pg_upgrade.
-
Seed-Daten und Fixtures für lokale Datenbanken: klein, idempotent und mit dem Schema versioniert
Referenzdaten (überall benötigt), Beispieldaten (Entwicklung und Demos) und Testdaten (von Tests erzeugt) trennen; den Seed als idempotenten Code mit Upserts auf natürlichen Schlüsseln schreiben, den Beispieldatensatz klein und benannt halten, ihn sowohl im Setup-Skript als auch in der CI nach den Migrationen ausführen, und Entwicklermaschinen nie mit rohen Produktionsdaten seeden.
-
Eine Append-only-Zeitreihentabelle in PostgreSQL entwerfen
Messwerte in einer nach Zeitbereich partitionierten Tabelle mit timestamptz speichern, einem zusammengesetzten Schlüssel aus Serie und Zeit, Indizes passend zum Abfragemuster (B-Tree je Serie, BRIN für zeitliche Scans über die gesamte Tabelle) sowie Aufbewahrung durch Abtrennen und Löschen von Partitionen statt DELETE; die Entscheidungen ergeben sich daraus, dass Zeilen in zeitlicher Reihenfolge ankommen und in ganzen Zeitscheiben wieder verschwinden.
-
Abgeleitete Daten in PostgreSQL speichern: generierte Spalten versus materialisierte Views
Eine generierte Spalte leitet einen Wert pro Zeile allein aus dieser Zeile ab, entweder virtuell (beim Lesen berechnet) oder gespeichert (beim Schreiben berechnet), und darf nur unveränderliche Ausdrücke verwenden; eine materialisierte View speichert das Ergebnis einer beliebigen Abfrage und ist nur so aktuell wie ihr letztes REFRESH. Gespeicherte generierte Spalten für Normalisierung je Zeile verwenden, die indiziert werden soll, materialisierte Views für teure Aggregate, die nachhinken dürfen, und eine gepflegte Zusammenfassungstabelle, wenn keines von beidem passt.
-
VACUUM, Autovacuum und Tabellen-Bloat
PostgreSQLs MVCC hinterlässt nach Updates und Deletes tote Zeilenversionen; VACUUM gibt diese frei und pflegt Statistiken sowie den Schutz vor Transaktions-ID-Wraparound. Autovacuum sollte aktiviert bleiben und für stark genutzte Tabellen abgestimmt werden.
-
Kurzlebige Datenbanken in Containern für Integrationstests
Die echte Datenbank-Engine wird für jeden Testlauf in einem Wegwerf-Container gestartet, die Daten liegen im Arbeitsspeicher, Migrationen werden einmal auf eine Vorlagendatenbank angewendet und pro Testdatei kopiert; so prüfen Tests den echten Planer, die echten Constraints und das Isolationsverhalten statt eines In-Memory-Ersatzes.
-
Transaktionsisolationsstufen in der Praxis
Read Committed, Repeatable Read und Serializable tauschen Nebenläufigkeit gegen Konsistenz; zu wissen, welche Anomalien jede Stufe zulässt, entscheidet, wann explizite Sperren oder Wiederholungsversuche nötig sind.
-
Datenbankänderungen ohne Ausfall: Expand und Contract
Ein Schema in drei einzeln auslieferbaren Schritten ändern: erweitern (neue Spalte oder Tabelle anlegen, alte behalten), migrieren (doppelt schreiben und in Häppchen nachfüllen), zusammenziehen (Altes entfernen, sobald aller Code das Neue nutzt); lange Sperren vermeiden, indem keine Tabelle in einem Statement umgeschrieben wird und lock_timeout jede Wartezeit begrenzt.
-
Testdaten ohne personenbezogene Produktivdaten
Entwicklungs-, CI- und Staging-Umgebungen realistische Daten geben, indem man sie generiert: Spalten klassifizieren, geseedete Generatoren schreiben, die die Validatoren der Anwendung bestehen, Volumen mit generate_series erzeugen, aus der Produktion nur Verteilungen übernehmen, generierte Datensätze erkennbar markieren und den Abkürzungsweg «einfach Prod dumpen» entfernen.
-
NULL in SQL: dreiwertige Logik und ihre Fallstricke
NULL bedeutet unbekannt, daher ergeben Vergleiche mit NULL unbekannt statt wahr oder falsch; WHERE verwirft Zeilen mit dem Ergebnis unbekannt, NOT IN mit einem NULL findet nichts, und Aggregatfunktionen überspringen NULLs. IS NULL, IS DISTINCT FROM und COALESCE gezielt einsetzen.
-
Nur-Lese-Wartungsmodus: Lesezugriffe bedienen, während Schreibzugriffe pausiert sind
Bei Speicherumzügen, Failovers und langen Migrationen kann ein Dienst weiterhin Lesezugriffe bedienen und Schreibzugriffe mit einer klaren Meldung verweigern, statt ganz auszufallen; PostgreSQLs default_transaction_read_only macht neue Transaktionen auf Datenbankebene als Rückfallebene schreibgeschützt, und HTTP 503 mit Retry-After sagt Clients, wann sie es erneut versuchen sollen. Der Modus braucht einen Schalter, eine für Nutzer sichtbare Meldung und eine Generalprobe.
-
Common Table Expressions und rekursive Abfragen mit WITH
WITH benennt eine Unterabfrage für den Rest einer Anweisung; WITH RECURSIVE wertet einen nicht-rekursiven Term aus und wiederholt danach einen rekursiven Term, bis er keine neuen Zeilen mehr liefert, wodurch sich Bäume und Graphen beliebiger Tiefe in einer einzigen Abfrage durchlaufen lassen. Einmal verwendete, nebenwirkungsfreie CTEs werden standardmässig in die äussere Abfrage eingefaltet, sofern nicht MATERIALIZED angegeben wird, und SEARCH- sowie CYCLE-Klauseln regeln Reihenfolge und Schleifen.
-
JSONB-Spalten: wofür sie taugen und wann eine eigene Spalte besser ist
jsonb speichert geparstes JSON in einer binären Form, die sich mit GIN indexieren und über Containment- und Pfadoperatoren abfragen lässt; es eignet sich für spärliche, extern definierte oder tatsächlich variable Attribute. Daten mit fester Struktur, Daten, die Constraints, Fremdschlüssel oder Aktualisierungen einzelner Felder benötigen, sowie grosse, häufig geänderte Dokumente gehören in gewöhnliche Spalten.
-
SQL-Injection mit parametrisierten Abfragen verhindern
SQL nie durch Aneinanderhängen nicht vertrauenswürdiger Zeichenketten aufbauen; Werte als Parameter übergeben, damit der Treiber sie getrennt vom Statement überträgt, und Identifikatoren, die dynamisch sein müssen, über eine Positivliste führen.
-
Datenbank-Connection-Pooling und seine Grenzen
Jede PostgreSQL-Verbindung ist ein Prozess mit Speicherkosten; Anwendungen sollten einen kleinen, an die tatsächliche Nebenläufigkeit angepassten Pool führen, Timeouts für den Verbindungsbezug setzen und Request-Handler nie ad hoc eigene Verbindungen öffnen lassen.
-
PostgreSQL-SKIP-LOCKED-Claims mit vier gleichzeitigen Queue-Konsumenten gemessen
Vier gleichzeitige Transaktionen beanspruchten je 25 synthetische Jobs in PostgreSQL 16.15. Die zurückgegebenen 100 IDs waren eindeutig, und kein Job blieb unbeansprucht; das bestätigt eine einzelne begrenzte Claim-Phase, nicht Exactly-once-Verarbeitung oder den Ersatz durch einen Broker.
-
Sagas: mehrstufige Workflows über mehrere Services mit Kompensation statt Rollback
Eine Saga ist eine Folge lokaler Transaktionen in verschiedenen Services, von denen jede die nächste auslöst; schlägt ein Schritt fehl, werden frühere Schritte durch vom Entwickler geschriebene Kompensationstransaktionen rückgängig gemacht. Sagas stellen Konsistenz ohne verteilte Transaktionen her, geben dafür aber Isolation auf, sodass Zwischenzustände sichtbar sind und Kompensationen bewusst entworfen statt vorausgesetzt werden müssen.
Maschinenlesbar: JSON