Daten in Amazon Redshift validieren

Ein praxisnaher Leitfaden zur Datenqualität in Amazon Redshift — die sechs Prüfungen, die jede Tabelle braucht, wie Sie sie aus der WLM-Queue heraushalten, die Falle der nicht durchgesetzten Constraints und wie Sie alles als versionierten Data Contract betreiben.

· 8 min read

Um Daten in Amazon Redshift zu validieren, formulieren Sie jede Erwartung als Aggregatabfrage, die eine Anzahl von Verstößen zurückgibt, und führen den Stapel nach jedem Ladelauf aus. Die sechs Prüfungen, die sich lohnen, sind: Nullwerte in Pflichtspalten, doppelte Schlüssel, Werte außerhalb einer erlaubten Menge, Zahlen außerhalb eines plausiblen Bereichs, fehlerhaft formatierte Zeichenketten und veraltete Zeilen. Wegen seiner Postgres-Abstammung ist das meiste SQL vertraut — zwei Dinge aber nicht: Constraints werden in Redshift deklariert und nie durchgesetzt, sodass der Optimizer aus einem doppelten Schlüssel falsche Antworten ableiten kann, und Validierungsabfragen konkurrieren um Slots in einer WLM-Queue, die auch Ihr ETL nutzt.

Warum Redshift Sorgfalt verlangt

Constraints sind Hinweise, keine Regeln. Redshift akzeptiert Deklarationen von PRIMARY KEY, UNIQUE und FOREIGN KEY und setzt keine davon je durch. Schlimmer noch: Der Planner vertraut ihnen. Wenn Sie order_id als eindeutig deklarieren und sie es nicht ist, kann eine Abfrage, die sich auf diese Annahme stützt, falsche Ergebnisse liefern und nicht bloß langsame. Eindeutigkeit zu validieren ist in Redshift keine vorsorgliche Hygiene — es schützt die Korrektheit jeder nachgelagerten Abfrage.

Alles teilt sich eine Queue. Redshift führt Abfragen über Workload Management aus. Ein Validierungsdurchlauf voller Full Table Scans, der zeitgleich mit dem nächtlichen ETL eingereicht wird, reiht sich dahinter ein — oder nimmt ihm, schlimmer noch, Slots weg. Geben Sie der Validierung eine eigene WLM-Queue mit moderater Nebenläufigkeit und eine Query Monitoring Rule, die alles abbricht, was über einer Schwelle läuft.

Veraltete Statistiken verändern, was „billig" heißt. Nach einem großen COPY sind die Tabellenstatistiken veraltet, bis ANALYZE läuft. Pläne, die aus veralteten Statistiken gewählt werden, können aus einem schnellen Aggregat einen Broadcast Join machen. Validieren Sie nach ANALYZE, nicht davor.

Jenseits dieser drei Punkte hat Validierung in Redshift dieselbe Gestalt wie überall sonst — der vollständige Leitfaden zur Datenvalidierung legt sie von Anfang bis Ende dar.

Die sechs Prüfungen, die jede Tabelle braucht

1. Vollständigkeit — Nullwerte in Pflichtspalten

SELECT COUNT(*) AS violations
FROM sales.orders
WHERE order_id IS NULL;

Redshift ist spaltenorientiert, liest hier also nur die Spalte order_id — billig selbst bei einer breiten Faktentabelle. Schreiben Sie in einer Prüfung nie SELECT *; damit verschenken Sie genau diesen Vorteil.

2. Eindeutigkeit — doppelte Geschäftsschlüssel

SELECT COUNT(*) AS violations
FROM (
    SELECT order_id
    FROM sales.orders
    WHERE order_id IS NOT NULL
    GROUP BY order_id
    HAVING COUNT(*) > 1
) dupes;

Das ist die Prüfung, die Sie auf jeder Redshift-Tabelle zuerst laufen lassen sollten. Duplikate entstehen regelmäßig: ein COPY, der nach einem Teilabbruch wiederholt wurde, ein als Delete-dann-Insert umgesetztes MERGE, bei dem der Delete-Filter danebenlag, ein Upstream-Extrakt, der für dasselbe Zeitfenster erneut lief. Da der deklarierte Primärschlüssel nichts tut, wird sie sonst nichts erwischen.

Hat die Tabelle einen Sort Key auf dem Geschäftsschlüssel, läuft das GROUP BY gegen sortierte Blöcke und ist deutlich günstiger. Es lohnt sich, Sort Keys mit diesem Gedanken auszuwählen.

3. Konformität — Werte außerhalb einer erlaubten Menge

SELECT COUNT(*) AS violations
FROM sales.orders
WHERE status IS NOT NULL
  AND status NOT IN ('pending', 'paid', 'shipped', 'refunded');

Behalten Sie die Null-Absicherung — NULL NOT IN (...) ergibt NULL, die Zeile fällt heraus, und eine Spalte mit vielen Nullwerten meldet sich sauber.

Längen von VARCHAR zählen in Redshift Bytes, nicht Zeichen. Ein Vier-Byte-Emoji in einer VARCHAR(10)-Spalte wird beim Laden abgeschnitten, und ein abgeschnittener Wert scheitert an der Prüfung auf erlaubte Werte aus einem Grund, der nichts mit dem Quellsystem zu tun hat. Dimensionieren Sie Textspalten großzügig.

4. Genauigkeit — Zahlen außerhalb eines plausiblen Bereichs

SELECT COUNT(*) AS violations
FROM sales.orders
WHERE total_amount IS NOT NULL
  AND (total_amount < 0 OR total_amount > 100000);

Nutzen Sie DECIMAL/NUMERIC für Geldbeträge. Die DECIMAL-Arithmetik von Redshift kann bei Aggregationen zudem still in eine größere Nachkommastellenzahl überlaufen — eine Bereichsprüfung auf der Rohspalte ist deshalb verlässlicher als eine auf einer berechneten Summe.

5. Konformität — fehlerhaft formatierte Identifier

Redshift behält die Regex-Operatoren von Postgres:

SELECT COUNT(*) AS violations
FROM sales.orders
WHERE reference IS NOT NULL
  AND reference !~ '^ORD-[0-9]{6}
#39;;

~ ist Groß-/Kleinschreibung-sensitiv, ~* nicht, !~ negiert. Auch SIMILAR TO sowie REGEXP_COUNT/REGEXP_SUBSTR stehen zur Verfügung. Es ist keine Musterübersetzung nötig — anders als bei SQL Server ist das Muster, das Sie schreiben, auch das Muster, das läuft.

6. Aktualität — Freshness

SELECT COUNT(*) AS violations
FROM sales.orders
WHERE created_at < GETDATE() - INTERVAL '24 hours';

GETDATE() liefert in Redshift UTC — das Gegenteil des Verhaltens in SQL Server und eine echte Quelle von Verwirrung, wenn man Regeln zwischen beiden portiert. Auch SYSDATE liefert UTC. Speichern Sie Zeitstempel als TIMESTAMP (Redshift speichert keine Zeitzone) und halten Sie per Konvention alles in UTC.

Für eine Prüfung auf abgeschlossene Ladeläufe, die keine Tabellendaten anfasst, trägt SVV_TABLE_INFO die Metadaten pro Tabelle günstig bei.

Referenzielle Integrität

SELECT COUNT(*) AS violations
FROM sales.orders o
LEFT JOIN sales.customers c ON o.customer_id = c.id
WHERE o.customer_id IS NOT NULL
  AND c.id IS NULL;

Weil Fremdschlüssel nicht durchgesetzt werden, sind verwaiste Zeilen nach einem teilweisen Backfill häufig. Für die Kosten dieser Prüfung zählt der Distribution Style: Sind beide Tabellen per DISTKEY auf der Join-Spalte verteilt, ist der Join lokal auf jedem Slice; andernfalls verteilt Redshift eine Seite über den Cluster um. Bei großen Tabellen ist das der Unterschied zwischen Sekunden und Minuten.

Ein sicherer Nutzer mit Lesezugriff

CREATE USER catalyst_ro PASSWORD '<generated>';
GRANT USAGE ON SCHEMA sales TO catalyst_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA sales TO catalyst_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA sales
  GRANT SELECT ON TABLES TO catalyst_ro;

Die Zeile mit den Default Privileges zählt hier genauso viel wie in Postgres: Tabellen, die das ETL von morgen neu erzeugt, sind für den Validierungsnutzer sonst unsichtbar, und Prüfungen scheitern plötzlich mit Berechtigungsfehlern, die sich wie Datenfehler lesen.

Danach isolieren Sie den Workload:

-- In the WLM configuration, give the validation user group its own queue with
-- low concurrency, and a query monitoring rule that aborts on long runtime.
CREATE GROUP validators WITH USER catalyst_ro;

Von Ad-hoc-SQL zum Data Contract

Die Erwartungen zu deklarieren macht sie nachvollziehbar, portabel und unabhängig davon, welches Tool die Tabelle lädt. Catalyst nutzt den Open Data Contract Standard:

apiVersion: v3.0.0
kind: DataContract
info:
  title: orders
  version: 1.3.0
  owner: data-platform
schema:
  - name: orders
    physicalName: orders
    physicalType: table
    properties:
      - name: order_id
        logicalType: string
        physicalType: varchar(36)
        required: true
        primaryKey: true
        quality:
          - rule: nullCount
            dimension: completeness
            severity: error
            mustBe: "0"
          - rule: duplicateCount
            dimension: uniqueness
            severity: error
            mustBe: "0"
      - name: customer_id
        logicalType: string
        quality:
          - rule: referentialIntegrity
            dimension: consistency
            severity: error
            mustBe: "customers.id"
      - name: status
        logicalType: string
        quality:
          - rule: validValues
            dimension: conformity
            severity: error
            mustBe: "['pending', 'paid', 'shipped', 'refunded']"
      - name: total_amount
        logicalType: number
        physicalType: numeric(12,2)
        quality:
          - rule: between
            dimension: accuracy
            severity: error
            mustBe: "[0, 100000]"
      - name: reference
        logicalType: string
        quality:
          - rule: regex
            dimension: conformity
            severity: warning
            mustBe: "'^ORD-[0-9]{6}
#39;" - name: created_at logicalType: timestamp quality: - rule: freshness dimension: timeliness severity: error mustBe: "<= 24h" quality: - rule: rowCount dimension: consistency severity: warning mustBe: "> 0"

Catalyst importiert die Spalten aus information_schema, schlägt einen Basis-Contract vor, kompiliert jede Regel zu Redshift-SQL und hält pro Prüfung pass, warn oder fail fest, samt einer Stichprobe der fehlerhaften Zeilen. Das YAML läuft verlustfrei durch den visuellen Builder — Kommentare und Reihenfolge bleiben erhalten —, sodass die Datei, die im Pull Request geprüft wird, auch die Datei ist, die ausgeführt wird.

Redshift-Stolperfallen, die man kennen sollte

FalleWas passiertWas zu tun ist
Nicht durchgesetzter PRIMARY KEYPlanner vertraut ihm, liefert falsche ErgebnisseImmer eine duplicateCount-Regel ergänzen
Nicht durchgesetzter FOREIGN KEYVerwaiste Zeilen nach Teil-BackfillsEine referentialIntegrity-Regel ergänzen
Geteilte WLM-QueuePrüfungen konkurrieren mit dem ETLEigene Queue + Query Monitoring Rule
Veraltete StatistikenAggregat wird zum Broadcast JoinNach ANALYZE validieren
VARCHAR-Längen in BytesMehrbyte-Text wird beim Laden abgeschnittenTextspalten großzügig dimensionieren
Kein ALTER DEFAULT PRIVILEGESNeue Tabellen sind morgen nicht lesbarDefault-Rechte auf dem Schema vergeben
GETDATE() liefert UTCGegenteil von SQL ServerAlles in UTC halten
Late-Binding-ViewsPrüfung scheitert, wenn die Basistabelle entfälltBasistabellen validieren, nicht Views

Zeitplanung und Alerting

Stoßen Sie die Validierung aus dem Abschluss des COPY oder des Transformationsjobs an, nach ANALYZE, statt von einer festen Uhrzeit aus. Auf Redshift Serverless gilt derselbe Rat mit einem zusätzlichen Anreiz: Ungenutzte Kapazität kostet nichts, aber ein Validierungsdurchlauf, der die Workgroup alle fünfzehn Minuten weckt, hält sie warm — und in der Abrechnung.

Alarmieren Sie auf Übergänge statt auf Dauerzustände, und differenzieren Sie den Schweregrad so, dass error den Prüfungen vorbehalten bleibt, die nachgelagerte Konsumenten wirklich blockieren sollten. Die Eindeutigkeitsregel gehört in Redshift fast immer auf error — angesichts dessen, was ein nicht durchgesetzter Primärschlüssel mit der Korrektheit von Abfragen anstellt.

Häufige Fragen

Setzt Redshift Primärschlüssel durch?

Nein. PRIMARY KEY, UNIQUE und FOREIGN KEY werden akzeptiert und festgehalten, beim Schreiben aber nie durchgesetzt. Der Query Planner vertraut ihnen allerdings, was bedeutet, dass ein doppelter Schlüssel eine Abfrage zu falschen Ergebnissen führen kann — nicht nur zu zusätzlichen Zeilen. Eindeutigkeit mit einer expliziten Prüfung zu validieren ist die einzige verfügbare Durchsetzung.

Kann ich Redshift-Daten validieren, ohne SQL zu schreiben?

Ja. Deklarieren Sie die Erwartung — Pflichtfeld, eindeutig, erlaubte Werte, numerischer Bereich, Regex, Höchstalter, Fremdschlüssel — und lassen Sie das Tool sie zu Redshift-SQL kompilieren. Catalyst importiert das Schema aus information_schema, schlägt einen Satz Basisregeln vor und hält handgeschriebenes SQL für wirklich maßgeschneiderte Logik über eine customSql-Regel bereit.

Wie verhindere ich, dass Validierungsabfragen mein ETL ausbremsen?

Stecken Sie den Validierungsnutzer in eine eigene WLM-Queue mit niedriger Nebenläufigkeit und einer Query Monitoring Rule, die lang laufende Abfragen abbricht, und planen Sie die Prüfungen im Anschluss an den Ladelauf statt parallel dazu. Halten Sie die Prüfungen spaltenbezogen — Redshift ist spaltenorientiert, ein Aggregat über eine einzelne Spalte ist also dramatisch billiger als alles, was die ganze Zeile anfasst.

Funktioniert das mit Redshift Serverless und Redshift Spectrum?

Redshift Serverless verhält sich für alles in diesem Leitfaden identisch; der einzige Unterschied ist die Abrechnung, vermeiden Sie also Zeitpläne, die die Workgroup unnötig wach halten. Externe Spectrum-Tabellen lassen sich problemlos validieren, aber es gibt keinen lokalen Speicher und keinen Sort Key, den man ausnutzen könnte — jede Prüfung scannt also die zugrunde liegenden S3-Objekte. Grenzen Sie sie auf eine Partition ein.

Welche Berechtigungen braucht ein Validierungstool?

USAGE auf dem Schema und SELECT auf den Tabellen, dazu Default Privileges, damit künftige Tabellen das Recht erben. Schreibzugriff ist nicht erforderlich. Catalyst verbindet sich read-only und speichert nur Metadaten und Prüfergebnisse.