Layer 8Ehrlicher Tech-Support

PostgreSQL: Abfragen finden Zeilen nach Systemupdate nicht

Die Sortierbibliothek des Betriebssystems hat sich geändert. PostgreSQL warnt vor einem Versions-Konflikt — Indizes auf Textspalten sind dann unbrauchbar.

Aufwand:
ca. 40 Min.
Voraussetzung:
Datenbankzugang mit Superuser-Rechten, psql, Wartungsfenster
Gilt für:
PostgreSQL 18

Das Symptom

Nach einem Betriebssystem-Update oder dem Wechsel auf ein neueres Container-Abbild läuft die Datenbank scheinbar normal. Dann häufen sich merkwürdige Meldungen aus der Fachabteilung: Ein Kunde ist über die Suche nicht auffindbar, obwohl sein Datensatz existiert. Eine Abfrage mit WHERE name = 'Müller' liefert nichts, WHERE name LIKE 'Mül%' dagegen schon. Eine UNIQUE-Bedingung lässt plötzlich zwei gleiche Werte zu.

Im Serverprotokoll steht dazu eine Warnung über einen Versions-Konflikt bei einer Collation: Sie sei in der Datenbank mit einer Version angelegt worden, das Betriebssystem liefere eine andere. Dazu der Hinweis, alle betroffenen Objekte neu aufzubauen und anschließend ALTER COLLATION ... REFRESH VERSION auszuführen.

Die „Layer 8“-Wahrheit

PostgreSQL sortiert Text nicht selbst. Es fragt die Sortierregeln beim Betriebssystem ab — bei der C-Bibliothek oder bei ICU. Diese Regeln sind kein Naturgesetz, sondern gepflegte Software, die sich mit jeder neuen Version ändern darf. Und genau daran hängt jeder B-Baum-Index über einer Textspalte: Er ist eine sortierte Struktur, aufgebaut nach der Reihenfolge, die zum Zeitpunkt des Aufbaus galt. Ändert sich die Reihenfolge, ist der Baum nicht mehr sortiert. Die Suche steigt an der falschen Stelle ab, findet nichts und meldet zufrieden: keine Treffer.

Das Tückische ist die Stille. Es gibt keinen Absturz, keinen Fehler in der Anwendung, keinen Eintrag im Fehlerprotokoll der Fachabteilung. Die Datenbank antwortet schnell und selbstbewusst — nur falsch. Bei einer UNIQUE-Bedingung bedeutet dasselbe Problem, dass eine Doppelung eingefügt werden darf, weil der Index den bereits vorhandenen Wert nicht findet. Diese Dubletten bleiben auch nach der Reparatur bestehen; das Neuindizieren deckt sie lediglich auf, indem es scheitert.

Der verbreitetste Fehler bei der Behandlung ist die Reihenfolge. Die Warnung nervt, ALTER COLLATION ... REFRESH VERSION macht sie weg, fertig. Das Handbuch weist ausdrücklich darauf hin, dass dabei nicht geprüft wird, ob alle betroffenen Objekte korrekt neu aufgebaut wurden. Das Auffrischen repariert also nichts, es beendet nur die Beschwerde. Erst neu indizieren, dann auffrischen — in dieser Reihenfolge und in keiner anderen.

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    Die betroffenen Objekte auflisten

    Das Handbuch liefert für diesen Zweck eine fertige Abfrage. Sie vergleicht die in der Datenbank vermerkte Collation-Version mit der, die das System gerade tatsächlich bereitstellt, und benennt jedes davon abhängige Objekt. Diese Liste ist der Arbeitsauftrag — nicht das Bauchgefühl, welche Tabellen wohl wichtig sind.

    SELECT pg_describe_object(refclassid, refobjid, refobjsubid) AS "Collation",
           pg_describe_object(classid, objid, objsubid) AS "Object"
      FROM pg_depend d JOIN pg_collation c
           ON refclassid = 'pg_collation'::regclass AND refobjid = c.oid
     WHERE c.collversion <> pg_collation_actual_version(c.oid)
     ORDER BY 1, 2;
    
  2. 2.

    Zuerst neu indizieren, nicht auffrischen

    Der vom Handbuch genannte Weg beginnt mit dem Neuaufbau aller abhängigen Objekte, zum Beispiel per REINDEX. Erst danach darf die Version aufgefrischt werden. Wer die Reihenfolge tauscht, verliert die einzige Anzeige, die ihn noch auf das Problem hinweist. REINDEX sperrt betroffene Tabellen; die Variante CONCURRENTLY dauert länger, hält den Betrieb dafür am Laufen.

    REINDEX DATABASE CONCURRENTLY meinedb;
    
  3. 3.

    Eindeutigkeit nachträglich prüfen

    Ein beschädigter Index über einer UNIQUE-Bedingung kann Doppelungen durchgelassen haben, solange er kaputt war. Beim Neuaufbau fliegt das auf: Tritt beim Neuindizieren ein Problem auf, etwa eine Verletzung der Eindeutigkeit, schlägt REINDEX laut Handbuch fehl und hinterlässt zusätzlich zum bestehenden Index einen als ungültig markierten neuen. Der wird bei Abfragen ignoriert, kostet aber weiterhin Aufwand bei jeder Änderung — solche Reste tragen die Endung _ccnew beziehungsweise _ccold und müssen vor dem nächsten Versuch von Hand mit DROP INDEX entfernt werden. Die Dubletten selbst sind fachlich zu bereinigen. Genau deshalb gehört dieser Schritt in ein Wartungsfenster und nicht in die Mittagspause.

  4. 4.

    Erst jetzt die Collation-Version auffrischen

    Sind alle abhängigen Objekte neu aufgebaut, wird der Systemkatalog auf die aktuelle Version gesetzt, und die Warnung verschwindet. Der Befehl steht so im Hinweis der Warnmeldung selbst. Der Name der Collation ist der aus der Meldung oder aus der Abfrage im ersten Schritt.

    ALTER COLLATION pg_catalog."de-DE-x-icu" REFRESH VERSION;
    
  5. 5.

    Die Wiederholung beim nächsten Update einplanen

    Das Handbuch stellt fest, dass so eine Änderung generell vermieden werden sollte, aber in legitimen Fällen vorkommt — bei einer neuen Hauptversion des Betriebssystems oder bei pg_upgrade auf Programmdateien mit neuerer ICU-Version. Daraus folgt eine Betriebsregel: Ein Distributionswechsel unter einem PostgreSQL-Server ist kein Routine-Update, sondern ein Vorgang mit anschließendem Neuindizieren. Wer das einplant, hat einen langen Abend. Wer es nicht einplant, hat wochenlang stille Falschauskünfte.

Häufige Fragen (FAQ)

?Im Protokoll steht, eine Collation habe einen Versions-Konflikt. Ist das nur ein Schönheitsfehler?

Nein, das ist die ernsteste Warnung, die PostgreSQL im Alltag ausgibt. Der Text lautet sinngemäß, die Collation sei in der Datenbank mit einer bestimmten Version angelegt worden, das Betriebssystem liefere aber eine andere. Das Handbuch erklärt dazu, dass eine Änderung an Collation-Definitionen zu beschädigten Indizes und anderen Problemen führen kann, weil das Datenbanksystem darauf baut, dass gespeicherte Objekte eine bestimmte Sortierreihenfolge haben. Ein Index, der nach der alten Reihenfolge aufgebaut wurde, wird mit der neuen Reihenfolge durchsucht — und liefert dann eben nicht alles.

?Woher kommt so eine Änderung, wenn ich an der Datenbank nichts gemacht habe?

Von außen. Das Handbuch nennt als legitime Auslöser ausdrücklich das Hochziehen des Betriebssystems auf eine neue Hauptversion und den Einsatz von pg_upgrade auf Server-Programmdateien, die gegen eine neuere ICU-Version gebunden sind. Die Sortierregeln kommen also nicht aus PostgreSQL, sondern aus der C-Bibliothek oder aus ICU. Wer den Server von einer Distributionsversion auf die nächste hebt oder das Container-Abbild wechselt, kann die Sortierreihenfolge mitverändert haben, ohne eine einzige Zeile SQL angefasst zu haben.

?Reicht es, ALTER COLLATION ... REFRESH VERSION auszuführen, damit die Warnung weggeht?

Die Warnung geht damit weg. Das Problem nicht. Das Handbuch beschreibt die Reihenfolge eindeutig: Wenn so etwas passiert, sollten alle von der Collation abhängigen Objekte neu aufgebaut werden, zum Beispiel mit REINDEX; ist das erledigt, kann die Collation-Version mit ALTER COLLATION ... REFRESH VERSION aufgefrischt werden. Und es fügt hinzu, dass dabei nicht geprüft wird, ob tatsächlich alle betroffenen Objekte korrekt neu aufgebaut wurden. Wer zuerst auffrischt, hat sich also nur die Anzeige abgeschaltet, die ihn auf kaputte Indizes hinweist.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

SWLästigconnection refused

PostgreSQL: Connection refused auf Port 5432

Die App erreicht die Datenbank nicht — Connection refused? Meist lauscht PostgreSQL nur auf localhost oder die Client-Freigabe in pg_hba.conf fehlt.

SWLästigpassword authentication failed for user

PostgreSQL: password authentication failed for user

PostgreSQL meldet „password authentication failed“? Falsches Passwort, falscher Nutzer oder pg_hba.conf erlaubt die Methode nicht. So kommst du rein.

SWLästigsorry, too many clients already

PostgreSQL: too many clients already

Die Datenbank weist neue Verbindungen ab? Das Verbindungslimit ist erreicht — meist, weil eine App Verbindungen nicht schließt oder ein Pool fehlt.