Datenvalidierung: der vollständige Leitfaden

Die sechs Prüfungen, die die meisten realen Vorfälle abfangen, wo sie laufen sollten, und wie aus Ad-hoc-SQL ein versionierter Data Contract wird, der nach Zeitplan läuft.

· 11 min read

Um Daten zu validieren, formulieren Sie jede Erwartung als Abfrage, die eine Anzahl verletzender Zeilen zurückgibt, führen den gesamten Satz nach jedem Ladevorgang gegen das Dataset aus und lassen die Prüfung fehlschlagen, sobald eine Anzahl einen zuvor vereinbarten Schwellenwert überschreitet. Sechs Prüfungen fangen die überwiegende Mehrheit realer Vorfälle ab: fehlende Werte in Pflichtspalten, doppelte Geschäftsschlüssel, Werte außerhalb einer erlaubten Menge, Zahlen außerhalb eines plausiblen Bereichs, fehlerhaft formatierte Zeichenketten und veraltete Zeilen. Die Prüfungen selbst sind gewöhnliches SQL — schwierig ist, sie dort auszuführen, wo die Daten liegen, sie mit dem Schema synchron zu halten und so zu alarmieren, dass niemand lernt, die Meldungen zu ignorieren. Alles Folgende ist die Maschinerie, um genau das zuverlässig zu tun.

Was Datenvalidierung tatsächlich ist

Drei Dinge werden Validierung genannt, und nur eines davon ist Thema dieses Leitfadens.

Eingabevalidierung findet am Rand einer Anwendung statt: Ein Formular weist eine E-Mail-Adresse ohne @ zurück. Sie ist ein Tor beim Schreiben, Datensatz für Datensatz.

Schemavalidierung prüft die Struktur — hat die Tabelle die Spalten, die der Loader erwartet, in den Typen, die er erwartet? Sie erkennt einen gebrochenen Vertrag zwischen Systemen, nicht fehlerhafte Werte innerhalb eines wohlgeformten.

Datenvalidierung prüft den Inhalt eines bereits existierenden Datasets, in großem Umfang, nachdem es gelandet ist: Wie viele der 4,2 Millionen Zeilen, die wir letzte Nacht geladen haben, brechen eine Zusage, auf die sich jemand verlässt?

Diese Unterscheidung bestimmt die Form der Lösung. Sie weisen keine Zeilen zurück; die Zeilen sind bereits da. Sie messen nach einem Zeitplan und entscheiden, was aus der Messung folgt. Ein Validierungslauf erzeugt eine Zahl je Regel, ein Bestehen oder Scheitern je Regel und eine Historie — und genau das macht aus „die Daten sehen komisch aus" den Satz „die NULL-Quote auf customer_id ist am vergangenen Dienstag um 04:12 Uhr von 0,02 % auf 11 % gesprungen". Wenn Sie die Definition für sich genommen suchen, inklusive der Abgrenzung von Testing, Observability und Bereinigung, beginnen Sie bei was Datenvalidierung ist und kommen für die Mechanik hierher zurück.

Die sechs Prüfungen, die jedes Dataset braucht

Jede Prüfung hat dieselbe Form. Zählen Sie die Zeilen, die gegen die Erwartung verstoßen, und vergleichen Sie die Anzahl mit einem Schwellenwert:

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

Das ist das gesamte Muster. Eine Regel ist ein Prädikat, eine Anzahl und ein Schwellenwert — und die sechs, auf die es ankommt, sind schlicht sechs Prädikate:

PrüfungDimensionFängt abPrädikat
VollständigkeitVollständigkeitEine Spalte, die nicht mehr befüllt wirdcol IS NULL
EindeutigkeitEindeutigkeitWiederholungsläufe, erneute Ladevorgänge, doppelt gezählter UmsatzGROUP BY key HAVING count(*) > 1
GültigkeitKonformitätEin neuer Enum-Wert, von dem Ihnen niemand erzählt hatcol NOT IN ('a', 'b', 'c')
WertebereichGenauigkeitEinheitenfehler, Währungsfehler, negative Mengencol < 0 OR col > 100000
FormatKonformitätFehlerhafte Bezeichner, abgeschnittene Codescol NOT LIKE / !~ pattern
FreshnessAktualitätEine Pipeline, die stillschweigend nicht mehr läuftmax_ts < now() - interval

Zwei Ergänzungen verdienen sich auf den meisten Tabellen ihren Platz: eine rowCount-Regel auf Tabellenebene, weil ein leeres Ergebnis nach einem Ladevorgang ein eigener und sehr häufiger Fehlerfall ist, und eine Prüfung der referenziellen Integrität auf Fremdschlüsseln, weil unvollständige Backfills Waisen hinterlassen, die Inner Joins stillschweigend verwerfen.

Die NULL-Falle, in die jeder einmal tappt

Schreiben Sie die Gültigkeitsprüfung so, wie sie oben steht, und sie wird Sie anlügen:

-- Wrong: nulls disappear from the count.
WHERE status NOT IN ('pending', 'paid', 'shipped', 'refunded')

-- Right:
WHERE status IS NOT NULL
  AND status NOT IN ('pending', 'paid', 'shipped', 'refunded')

NULL NOT IN (...) ergibt in jeder SQL-Engine NULL, nicht true. Ohne die Absicherung meldet eine Spalte, die zu 90 % NULL ist, perfekte Konformität. Das ist das mit Abstand häufigste falsche „bestanden" in handgeschriebenem Datenqualitäts-SQL, und es lohnt sich, jede geerbte Regel darauf abzuklopfen.

Wo die Prüfungen laufen sollten

Lassen Sie sie im Data Warehouse laufen, über eine Nur-Lese-Verbindung, und bewegen Sie die Zeilen nie.

Daten herauszuziehen, um sie zu validieren, ist aus drei Gründen der falsche Reflex: Es ist langsam, es kopiert sensible Zeilen in ein zweites System mit einer zweiten Sicherheitsprüfung, und es skaliert nicht — eine Prüfung, die eine Faktentabelle mit einer Milliarde Zeilen exportieren muss, wird nicht stündlich laufen. Die Aggregation in die Engine hinunterzudrücken bedeutet, dass jede Prüfung ein einziges SELECT ist, das eine Zahl zurückgibt — genau die Last, für die jedes Data Warehouse gebaut ist.

Der Rechtesatz ist wirklich minimal: Verbinden auf der Datenbank, Lesen des Schemakatalogs, SELECT auf den geprüften Tabellen. Sonst nichts. Wenn ein Validierungswerkzeug Schreibzugriff verlangt, fragen Sie nach dem Warum. Richten Sie die Verbindung auf ein Read Replica, wo es eines gibt — es handelt sich um Aggregat-Scans ohne Konsistenzanforderung jenseits von „aktuell" — und setzen Sie ein Abfrage-Timeout, damit ein nicht indizierter Scan keine Verbindung eine Stunde lang blockiert.

Manuelles SQL, ein Framework oder ein verwalteter Dienst

Es gibt drei ehrliche Wege, und der richtige hängt davon ab, wie viele Datasets Sie haben und wer die Regeln lesen können muss.

AnsatzGut inScheitert, wenn
Handgeschriebenes SQL im CronNull Einrichtung, volle Kontrolle, kein neuer AnbieterRegeln vom Schema abdriften; niemand weiß, welche Skripte noch laufen
Ein Framework (dbt-Tests, Great Expectations, Soda)Versionskontrolliert, läuft in Ihrer PipelineRegeln an das Format dieses Runners gebunden sind; nur abgedeckt ist, was dem Werkzeug gehört
Ein verwalteter ValidierungsdienstZeitplanung, Historie, Alarmierung und eine Oberfläche, die auch Nicht-Entwickler lesenSie einem Anbieter eine Verbindung anvertrauen und das Regelformat üblicherweise seines ist

Der Fehlermodus des ersten Wegs ist Entropie: Innerhalb eines Jahres haben Sie vierzig SQL-Dateien, sechs davon referenzieren gelöschte Spalten, und niemand traut sich, eine davon zu entfernen. Der Fehlermodus des zweiten ist Reichweite — dbt-Tests sind ausgezeichnet, decken aber nur Modelle ab, die dbt baut, und sie laufen, wenn dbt läuft. Der Fehlermodus des dritten ist Lock-in, und genau deshalb gibt es den nächsten Abschnitt.

Nichts davon schließt einander aus. Teams, die das gut lösen, legen schnelle, billige Assertions in die Pipeline, wo sie einen Build scheitern lassen, und bewahren die dauerhaften Zusagen dort auf, wo sie geprüft und überwacht werden — unabhängig davon, welches Werkzeug die Tabelle heute geschrieben hat.

Data Contracts: die Erwartungen versionieren, nicht die Skripte

Die dauerhafte Antwort auf Regel-Entropie besteht darin, Prüfungen nicht mehr als Code zu schreiben, sondern als Dokument — eine Erklärung dessen, was das Dataset zusagt, abgelegt neben Ihrem übrigen Quellcode, im Pull Request geprüft und von welchem Runner auch immer ausgeführt. Dieses Dokument ist ein Data Contract.

Der Open Data Contract Standard ist die offene Spezifikation, um einen solchen zu schreiben. Er ist YAML, er wird im Rahmen des Bitol-Projekts der Linux Foundation entwickelt statt von einem Anbieter, und ein minimaler Contract für die obigen Prüfungen sieht so aus:

apiVersion: v3.0.0
kind: DataContract
info:
  title: orders
  version: 1.0.0
  owner: data-platform
schema:
  - name: orders
    physicalName: orders
    physicalType: table
    properties:
      - name: order_id
        logicalType: string
        required: true
        primaryKey: true
        quality:
          - rule: nullCount
            dimension: completeness
            severity: error
            mustBe: "0"
          - rule: duplicateCount
            dimension: uniqueness
            severity: error
            mustBe: "0"
      - name: status
        logicalType: string
        quality:
          - rule: validValues
            dimension: conformity
            severity: error
            mustBe: "['pending', 'paid', 'shipped', 'refunded']"
      - name: total_amount
        logicalType: number
        quality:
          - rule: between
            dimension: accuracy
            severity: error
            mustBe: "[0, 100000]"
      - name: created_at
        logicalType: timestamp
        quality:
          - rule: freshness
            dimension: timeliness
            severity: error
            mustBe: "<= 24h"
    quality:
      - rule: rowCount
        dimension: completeness
        severity: warning
        mustBe: "> 0"

Drei Eigenschaften machen den Aufwand lohnend.

Er ist portabel. nullCount bedeutet überall dasselbe; der Runner kompiliert es in den Dialekt der jeweiligen Engine. Ein Wechsel des Data Warehouse ist damit keine Regelmigration mehr.

Er ist prüfbar. Eine Schwellenwertänderung ist ein Diff mit einem Autor und einer Begründung. Ob eine Grenze verschoben wurde, weil sich das Geschäft geändert hat oder weil jemand den Alarm satthatte, wird damit nachvollziehbar — was es in einer Anbieteroberfläche nie ist.

Er gehört Ihnen. Regeln, die in einem offenen Standard geschrieben sind, sind kein Vermögenswert desjenigen, der sie heute ausführt.

Catalyst setzt direkt auf ODCS auf: Das YAML ist das Speicherformat und nicht die Darstellung einer Datenbankzeile. Eine im visuellen Builder bearbeitete Regel erzeugt deshalb einen einzeiligen Diff, und der im Pull Request geprüfte Contract ist Byte für Byte derselbe, der ausgeführt wird.

Zeitplanung und Alarmierung

Zwei Regeln, beide auf die harte Tour gelernt.

Lösen Sie aus dem Ladevorgang aus, nicht nach der Uhr. Eine Tagestabelle, die um 06:00 Uhr validiert wird, während das ELT um 06:40 Uhr fertig wird, scheitert jeden Morgen aus einem Grund, der nichts mit Qualität zu tun hat. Passen Sie den Takt an die Daten an: stündliche Freshness auf einer Streaming-Tabelle, ein Lauf nach dem nächtlichen Batch für alles andere. Prüfungen häufiger laufen zu lassen, als sich die Daten ändern, erzeugt Rauschen — und auf nutzungsbasiert abgerechneten Data Warehouses eine Rechnung.

Alarmieren Sie bei Übergängen, nicht bei Zuständen. „Orders hat angefangen zu scheitern" ist handlungsleitend. „Orders scheitert immer noch", stündlich wiederholt, ist der Weg, auf dem ein Channel stummgeschaltet wird — und ein stummgeschalteter Channel ist schlimmer als gar keine Alarmierung, weil er wie Abdeckung aussieht.

Nutzen Sie die Severity, um die beiden Regelpopulationen zu trennen. Reservieren Sie error für Prüfungen, die einen nachgelagerten Konsumenten tatsächlich blockieren sollten: eine Dashboard-Aktualisierung, einen Reverse-ETL-Abgleich, einen Finanzbericht. Alles andere — Musterprüfungen auf manuell erfassten Feldern, Drift in der Zeilenzahl, Auffälligkeiten in der Verteilung — gehört auf warning, wo es eine Trendlinie ist und kein Pager-Alarm.

Welche Datasets zuerst validieren?

Sie können nicht alles validieren, und der Versuch ist der Weg, auf dem das Projekt stirbt. Ordnen Sie nach Schadensradius:

  1. Alles, was in eine Zahl fließt, die eine Führungskraft liest. Umsatz, Personalbestand, Pipeline. Eine falsche Zahl kostet hier Glaubwürdigkeit, deren Wiederaufbau Monate dauert.
  2. Alles, was in eine automatisierte Entscheidung fließt. Preisgestaltung, Kreditlimits, ML-Features, Reverse-ETL in ein CRM. Diese Systeme handeln auf Basis schlechter Daten, bevor ein Mensch sie sieht.
  3. Alles mit einem externen Konsumenten. Ein Partner-Feed oder eine regulatorische Meldung hat Fehlerkosten, die Sie nicht kontrollieren.
  4. Die Joins im Kern Ihres Modells. Die Dimensionstabellen, an die alles joint und bei denen ein verwaister Schlüssel stillschweigend Zeilen aus jeder nachgelagerten Abfrage entfernt.

Beginnen Sie mit fünf bis zehn Regeln auf einer solchen Tabelle statt mit drei Regeln auf vierzig. Eine Abdeckung, die überall flach ist, sagt Ihnen nichts; eine Abdeckung, die auf den entscheidenden Tabellen tief geht, fängt genau die Vorfälle ab, von denen Sie sonst von jemand anderem erfahren.

Lesen Sie danach den Leitfaden zu Ihrer Engine — die sechs Prüfungen sind universell, das SQL, die Fallen und das Kostenmodell sind es nicht:

Catalyst setzt genau den beschriebenen Ablauf um — Schema importieren, einen Basisvertrag vorschlagen, jede Regel in das SQL Ihrer Engine kompilieren, sie nach Zeitplan ausführen und die pass/warn/fail-Historie je Regel verfolgen — über all diese Verbindungen hinweg, mit einem kostenlosen Plan, um es an einem Dataset auszuprobieren (PostgreSQL und MySQL), bevor Sie sich festlegen (Preise).

Häufig gestellte Fragen

Was gilt als Datenvalidierungsprüfung?

Eine Datenvalidierungsprüfung ist eine vereinbarte Erwartung an den Inhalt eines Datasets, ausgedrückt als Abfrage, die eine Anzahl verletzender Zeilen zurückgibt — keine fehlenden Werte in einer Pflichtspalte, keine doppelten Schlüssel, Werte innerhalb einer erlaubten Menge oder eines plausiblen Bereichs, korrekt formatierte Zeichenketten oder Zeilen, die aktuell genug sind, um nützlich zu sein. Die Prüfung scheitert, wenn diese Anzahl einen von Ihnen vorab gesetzten Schwellenwert überschreitet. Anders als die Eingabevalidierung läuft sie in großem Umfang gegen Daten, die bereits gelandet sind.

Was sind die wichtigsten Arten von Datenvalidierungsprüfungen?

Sechs decken die meisten realen Vorfälle ab: Vollständigkeit (NULL-Werte in Pflichtspalten), Eindeutigkeit (doppelte Geschäftsschlüssel), Gültigkeit (Werte außerhalb einer erlaubten Menge), Genauigkeit (Zahlen außerhalb eines plausiblen Bereichs), Konformität (Zeichenketten, die ein vorgeschriebenes Format verfehlen) und Aktualität (veraltete Zeilen oder Partitionen). Zeilenzahlen auf Tabellenebene und referenzielle Integrität zwischen Tabellen sind die beiden häufigsten Ergänzungen.

Muss ich SQL schreiben, um Daten zu validieren?

Für die Standardprüfungen nicht. Wenn Sie die Erwartung deklarieren — Pflichtfeld, eindeutig, erlaubte Werte, Zahlenbereich, Muster, maximales Alter, Fremdschlüssel —, kann ein Runner sie in das korrekte SQL Ihrer Engine kompilieren, was zugleich die Dialektunterschiede und die NULL-Fallen beseitigt. Handgeschriebenes SQL lohnt sich nur für wirklich maßgeschneiderte Geschäftslogik, über eine eigene SQL-Regel.

Wie oft sollten Datenvalidierungen laufen?

Passen Sie den Zeitplan an den Takt der Daten an und lösen Sie aus dem Job aus, der sie erzeugt, nicht zu einer festen Uhrzeit. Streaming-Tabellen wollen stündliche Freshness-Prüfungen; Batch-Tabellen wollen einen Lauf nach Abschluss des Ladevorgangs. Häufiger zu prüfen, als sich die Daten ändern, erzeugt nur Rauschen — und auf nutzungsbasiert abgerechneten Data Warehouses zusätzlich eine Rechnung.

Ist Datenvalidierung dasselbe wie ein Data Contract?

Nein. Validierung ist das Ausführen der Prüfungen; ein Data Contract ist das versionierte Dokument, das festhält, wie die Prüfungen lauten sollen. Der Contract trägt außerdem Eigentümerschaft, Beschreibungen und Service Levels — und genau das macht ihn für die Konsumenten der Daten prüfbar und nicht nur für das Team, das die Pipeline geschrieben hat. Ein Standard wie ODCS hält den Contract zwischen verschiedenen Runnern portabel.

Braucht Datenvalidierung Schreibzugriff auf meine Datenbank?

Nein. Jede hier beschriebene Prüfung ist ein SELECT, das eine einzige Zahl zurückgibt. Lesezugriff auf die Tabellen plus die Möglichkeit, den Schemakatalog zu lesen, sind der vollständige Rechtesatz. Wo ein Read Replica oder ein lesbares sekundäres Replikat existiert, richten Sie die Verbindung darauf — die Prüfungen haben keine Konsistenzanforderung jenseits von „aktuell", und sie von der Primärdatenbank wegzunehmen entkräftet den wichtigsten betrieblichen Einwand dagegen, sie häufig auszuführen.