Datenqualität auf Azure Databricks: dbt-Tests und Lakeflow-Expectations im Vergleich

Azure Databricks17 Min. LesezeitStand: August 2026

Datenqualität auf Azure Databricks

dbt entscheidet über den Lauf, Lakeflow über die einzelne Zeile.

dbt-Testsentscheiden über den Lauf
Wirkzeitpunktnach der Materialisierung
Fehlerhafte Zeilebleibt in der Tabelle, bleibt abfragbar
StärkeSchlüssel, Referenzen, Toleranzschwellen
Lakeflow-Expectationsentscheiden über die Zeile
Wirkzeitpunktwährend des Durchlaufs, je Datensatz
Fehlerhafte Zeileschreiben, verwerfen oder Lauf abbrechen
StärkeRegeln auf Ebene der einzelnen Zeile

Wer die Tabelle schreibt, prüft sie. Der Liefertakt entscheidet, ob eine nachgelagerte Prüfung überhaupt einen Zeitpunkt hat.

Ein dbt-Test ist eine Abfrage gegen eine Tabelle, die es bereits gibt. Eine Expectation in Lakeflow pipelines ist eine Klausel in der Anweisung, die die Tabelle erzeugt, und sie wird für jeden Datensatz ausgewertet, der durch die Abfrage läuft. Beide prüfen dieselben Daten, und beide beschreiben ihre Regel in SQL. Sie unterscheiden sich darin, worüber sie entscheiden: dbt entscheidet über den gesamten Lauf, Lakeflow über die einzelne Zeile.

Dieser Artikel beantwortet, welche Prüfung in welches Werkzeug gehört, was dabei ungedeckt bleibt und wie Sie zwischen beiden auswählen. Die Empfehlungen am Ende stammen aus unseren Projekten und sind als Erfahrung gekennzeichnet, alles Übrige ist gegen die Produktdokumentation geprüft.

Zur Namensgebung, weil sie sich zweimal geändert hat: Das Produkt hieß Delta Live Tables, danach Lakeflow Declarative Pipelines und heißt in der aktuellen Azure-Dokumentation Lakeflow pipelines. Es erweitert Apache Spark Declarative Pipelines, das quelloffene Framework. Die dbt-Beispiele laufen über den Adapter dbt-databricks und gelten auch außerhalb von Azure. Der Azure-Bezug liegt in Unity Catalog, den Rechten und der Produktvariante.

Die zwei Mechanismen

Ein Data Test in dbt ist eine Abfrage, die alle Zeilen zurückgibt, die Sie nicht haben wollen. Sie läuft, nachdem das Modell materialisiert wurde. Die vier eingebauten generischen Tests decken Eindeutigkeit, Pflichtfelder, Wertelisten und referentielle Integrität ab.

YAML
# Argumente werden ab dbt 1.10.5 unter arguments verschachtelt
models:
  - name: stg_deliveries
    columns:
      - name: delivery_id
        data_tests:
          - unique
          - not_null
      - name: status
        data_tests:
          - accepted_values:
              arguments:
                values: ['angelegt', 'unterwegs', 'zugestellt', 'storniert']
      - name: customer_id
        data_tests:
          - relationships:
              arguments:
                to: ref('stg_customers')
                field: customer_id

Eine Expectation ist ein SQL-Wahrheitsausdruck innerhalb der Erzeugungsanweisung einer Streaming Table, einer Materialized View oder einer temporären View. Sie wird auf jeden durchlaufenden Datensatz angewendet, und Sie legen fest, was mit einem fehlerhaften Datensatz geschieht.

SQL
-- Die Klausel gehört in die Erzeugungsanweisung, nicht daneben
CREATE OR REFRESH STREAMING TABLE stg_deliveries(
  CONSTRAINT gueltiger_status EXPECT (status IN ('angelegt', 'unterwegs', 'zugestellt', 'storniert'))
) AS SELECT * FROM STREAM(raw.deliveries);

Aus diesem Unterschied im Zeitpunkt folgt alles Weitere. Weil dbt nach der Materialisierung prüft, kann es Aussagen über die fertige Tabelle treffen. Weil eine Expectation während des Durchlaufs prüft, liegt ihr im Moment der Auswertung nur eine Zeile vor.

Was dbt für Datenqualität mitbringt

Über die vier eingebauten Tests hinaus liefern die Packages dbt_utils und dbt_expectations fertige generische Tests für Wertebereiche, Datentypen, Zeichenlängen, Muster und statistische Kennzahlen. Wiederkehrende eigene Regeln lassen sich als Custom Generic Test einmal schreiben und danach parametrisiert anwenden. Wie das im Einzelnen aussieht, steht in unserem Artikel zu dbt-Tests auf Azure Databricks.

Zwei Konfigurationen entscheiden über die Betriebstauglichkeit. severity steuert, ob ein Fehlschlag den Lauf abbricht oder nur meldet, und error_if sowie warn_if machen daraus Schwellenwerte. Beide sind mit !=0 vorbelegt, severity selbst mit error. store_failures_as legt die fehlerhaften Zeilen als Tabelle oder View ab, damit sie für die Ursachenanalyse abfragbar bleiben. Der Vorgabewert ist ephemeral, es wird also nichts gespeichert, solange Sie es nicht einschalten.

YAML
models:
  - name: fct_delivery_items
    columns:
      - name: delivery_id
        data_tests:
          - relationships:
              arguments:
                to: ref('fct_deliveries')
                field: delivery_id
              config:
                severity: error
                store_failures_as: table
      - name: quantity
        data_tests:
          - dbt_expectations.expect_column_values_to_be_between:
              arguments:
                min_value: 1
                max_value: 5000
              config:
                # unter zehn Verstößen nur Warnung, ab 500 Abbruch
                severity: error
                warn_if: ">10"
                error_if: ">500"

Die Auswertungsreihenfolge sorgt regelmäßig für Verwirrung. Bei severity: error prüft dbt zuerst error_if, und erst wenn diese Bedingung nicht zutrifft, danach warn_if. Bei severity: warn wird error_if vollständig übersprungen. Wer eine Schwelle setzt und die Severity dabei auf warn lässt, bekommt also nie einen Fehler.

Der zweite Hebel ist die Orchestrierung. Bei dbt build blockiert ein fehlgeschlagener Test auf einem Modell die nachgelagerten Modelle, sie werden übersprungen. Das ist der dokumentierte Weg, fehlerhafte Daten aufzuhalten, und wer das nicht will, senkt Severity oder Schwelle. Die seit dbt 1.12 verfügbare Konfiguration on_error: continue hilft hier nicht, denn sie gilt ausschließlich für Modelle und hat auf Tests keine Wirkung.

Für Quellen prüft dbt source freshness die Aktualität gegen warn_after und error_after, wahlweise über eine Zeitstempelspalte oder über eine eigene Abfrage. Das ist ein eigener Befehl und nicht Teil von dbt build. Beachten Sie den Zuschnitt: Die Prüfung gilt für Sources, nicht für die Modelle, die dbt selbst schreibt.

Die Grenze von dbt liegt an zwei Stellen. Ein Data Test läuft, nachdem die Zeile geschrieben wurde, und er kann eine einzelne Zeile nicht aussortieren und den Rest weiterlaufen lassen. Und er läuft nur, wenn jemand dbt startet, zwischen zwei Läufen findet keine Prüfung statt.

Was Lakeflow pipelines mitbringt

Für jede Expectation legen Sie eine von drei Aktionen fest. Ohne Zusatz gilt warn: Die fehlerhafte Zeile wird geschrieben und in den Metriken gezählt. ON VIOLATION DROP ROW verwirft sie vor dem Schreiben und protokolliert die Anzahl. ON VIOLATION FAIL UPDATE bricht das Update ab, und bei einem Tabellen-Update rollt das System die Transaktion atomar zurück.

SQL
CREATE OR REFRESH STREAMING TABLE stg_delivery_items(
  -- geschrieben und gezählt
  CONSTRAINT plausible_menge EXPECT (quantity BETWEEN 1 AND 5000),
  -- verworfen, der Lauf geht weiter
  CONSTRAINT positiver_preis EXPECT (unit_price > 0) ON VIOLATION DROP ROW,
  -- bricht ab und rollt zurück
  CONSTRAINT hat_schluessel EXPECT (delivery_id IS NOT NULL) ON VIOLATION FAIL UPDATE
) AS SELECT * FROM STREAM(raw.delivery_items);

Bei FAIL UPDATE hängt die Wirkung am Pipeline-Modus, und dieser Zusammenhang wird beim Schreiben der Regel leicht übersehen. In einer triggered Pipeline scheitert nur der betroffene Flow, andere parallele Flows laufen weiter. In einer continuous Pipeline stoppt der Flow, alle abhängigen Flows stoppen ebenfalls, und die Pipeline gibt eine Meldung mit dem Grund aus. Dieselbe Zeile Code hat also je nach Modus eine sehr unterschiedliche Reichweite.

Der zweite Punkt betrifft die Sichtbarkeit. Metriken werden nur für warn und drop erfasst, bei fail gar nicht, weil das Update abbricht. Und die Metriken sind Zähler, keine Zeilen. Wer die fehlerhafte Zeile für die Ursachenanalyse braucht, bekommt sie über DROP ROW nicht zurück.

Genau deshalb ist Quarantäne nicht die Ergänzung zu DROP ROW, sondern die Alternative dazu. Das dokumentierte Muster arbeitet mit warn, berechnet eine Kennzeichnungsspalte und trennt danach über zwei Views.

SQL
-- Alle Zeilen laufen durch, die Kennzeichnung entscheidet
CREATE OR REFRESH TEMPORARY STREAMING TABLE delivery_items_quarantaene(
  CONSTRAINT quarantaene_zeile EXPECT (unit_price > 0 AND quantity IS NOT NULL)
)
PARTITIONED BY (is_quarantined)
AS SELECT
     *,
     NOT (unit_price > 0 AND quantity IS NOT NULL) AS is_quarantined
   FROM STREAM(raw.delivery_items);

CREATE TEMPORARY VIEW delivery_items_gueltig AS
  SELECT * FROM delivery_items_quarantaene WHERE is_quarantined = FALSE;

CREATE TEMPORARY VIEW delivery_items_fehlerhaft AS
  SELECT * FROM delivery_items_quarantaene WHERE is_quarantined = TRUE;

Für die Wiederverwendung über mehrere Datasets hinweg lassen sich Regeln seit Anfang 2026 in Unity-Catalog-Tabellen ablegen und pipelineübergreifend teilen. Die Anwendung läuft dabei über Python, denn die Gruppierung mehrerer Expectations gibt es nur dort, und die Dokumentation hält fest, dass dynamisches Laden von Expectations in SQL nicht unterstützt wird.

Auch Lakeflow pipelines kennen inzwischen Unit-Tests, seit Juli 2026 in Beta. Sie laufen im Lakeflow Pipelines Editor gegen Mock-Daten und decken ausdrücklich auch Expectations ab. Die Voraussetzungen sind allerdings streng: Owner-Recht auf der Pipeline, USE CATALOG und CREATE SCHEMA auf dem Standardkatalog, der Kanal PREVIEW, triggered Modus und Python für die Tests selbst.

Die Grenze von Expectations ist eine einzige, aber eine folgenreiche. Der Ausdruck darf keine Subquery auf eine andere Tabelle enthalten, ebenso wenig eigene Python-Funktionen oder externe Aufrufe. Damit ist jede Aussage über eine Menge ausgeschlossen, also Eindeutigkeit, referentielle Integrität und Mengenvergleiche.

Deckung und Lücken

Damit stehen die beiden Lücken fest, um die es in diesem Artikel geht. dbt greift nicht in den Schreibvorgang ein und prüft nur dann, wenn jemand es startet. Lakeflow kann über eine Menge nichts aussagen. Alles Weitere ist die Frage, was das Schließen der jeweiligen Lücke kostet.

Diese drei Prüfungen, Eindeutigkeit, referentielle Integrität und Mengenvergleich, lassen sich in Lakeflow nachbauen. Jede kostet allerdings ein eigenes Validierungs-Dataset. Für die Eindeutigkeit eines Schlüssels sieht das so aus:

SQL
-- In dbt eine Zeile YAML, hier eine eigene Materialized View
CREATE OR REFRESH MATERIALIZED VIEW deliveries_pk_test(
  CONSTRAINT eindeutiger_schluessel EXPECT (num_entries = 1) ON VIOLATION FAIL UPDATE
) AS SELECT delivery_id, count(*) AS num_entries
     FROM deliveries
     GROUP BY delivery_id;

Ein solches Validierungs-Dataset hat eine Eigenschaft mit Folgen für die Orchestrierung: Es sperrt seine nachgelagerten Tabellen nicht. Ein anderes Dataset, das die Validierungstabelle liest, wartet nicht auf deren Ergebnis, eine fehlgeschlagene Validierung hält also nachgelagerte Aktualisierungen nicht auf. Wer das braucht, trennt Validierung und Weiterverarbeitung in zwei Pipelines und verbindet sie über einen Job mit abhängigen Tasks.

PrüfungdbtLakeflow pipelinesEinordnung
Pflichtfeld, Werteliste, Wertebereich, Muster, Längenot_null und accepted_values eingebaut, Bereich, Muster und Länge über dbt_expectationsje eine Klausel CONSTRAINT ... EXPECTBeide vollständig, vergleichbarer Aufwand
Eindeutigkeit eines Schlüsselsunique, zusammengesetzt über dbt_utilseigene Materialized View je SchlüsselBeide möglich, in Lakeflow je Schlüssel ein eigenes Dataset
Referentielle Integritätrelationshipseigene Materialized View je BeziehungBeide möglich, in Lakeflow je Beziehung ein eigenes Dataset
Mengengleichheit zweier Tabellendbt_utils.equal_rowcounteigene Materialized ViewBeide möglich, in Lakeflow als eigenes Dataset
Datentyp und Spaltenliste der QuelleTyp- und Schema-Tests aus dbt_expectationskeine EntsprechungNur in dbt möglich
Toleranzschwelle je Prüfungerror_if, warn_if, fail_calckeine EntsprechungNur in dbt möglich
Aktualität der Quelledbt source freshnesskeine EntsprechungNur in dbt, in Lakeflow ersatzweise über Anomaly Detection
Fehlerhafte Zeile einzeln verwerfenkeine Entsprechung im TestON VIOLATION DROP ROWNur in Lakeflow möglich
Lauf abbrechen und zurückrollennur über erzwungenen Contract, alles oder nichtsON VIOLATION FAIL UPDATENur in Lakeflow gezielt, in dbt nur für das ganze Modell
Fehlerhafte Zeilen als Tabellestore_failures_asnur Zähler, Zeilen über Quarantäne-MusterIn dbt eine Konfiguration, in Lakeflow das Quarantäne-Muster
Nachgelagerte Objekte sperrendbt build überspringt siegetrennte Pipelines plus Job nötigIn dbt eingebaut, in Lakeflow nur mit einer zweiten Pipeline
Logikprüfung gegen TestdatenUnit-Tests, lokal und in der CIPipeline-Unit-Tests, Beta, nur im EditorIn dbt produktiv einsetzbar, in Lakeflow noch Beta
Bibliothek fertiger Prüfungendbt Hub, vor allem dbt_utils und dbt_expectationsRegeltabelle in Unity Catalog, Anwendung über PythonIn dbt größere Auswahl, in Lakeflow Eigenbau über Python

Die Bilanz ist eindeutig: dbt deckt mehr ab. Alles, was mehr als eine Zeile ansieht, dazu Toleranzschwellen und Quellaktualität, gibt es dort fertig. In Lakeflow gibt es das entweder gar nicht oder nur als eigenes Validierungs-Dataset je Regel, und jedes davon ist ein Objekt mehr, das jemand baut, benennt und betreibt. Umgekehrt deckt Lakeflow genau das ab, was dbt strukturell nicht kann: die Entscheidung über die einzelne Zeile im Moment des Schreibens.

Daraus folgt aber nicht, dass dbt die bessere Wahl ist. Die breitere Deckung nützt nichts, wenn eine Lakeflow-Pipeline die Tabelle schreibt, denn dann kommt dbt erst danach zum Zug und ändert am Schreibvorgang nichts mehr. Die Frage lautet deshalb nicht, welches Werkzeug mehr kann, sondern welche der beiden Lücken Ihre Strecke überhaupt trifft. Die hervorgehobenen Zeilen sind die, an denen sich das entscheidet.

Was auf Azure Databricks zu beachten ist

Product Edition. Expectations setzen die Edition ADVANCED voraus. Das Feld ist optional und mit ADVANCED vorbelegt, es betrifft Sie also nur, wenn jemand die Edition bewusst auf CORE oder PRO gesenkt hat. Passiert das, meldet die Pipeline einen Fehler mit Angabe des Grundes.

Objektgrenzen. Expectations funktionieren auf Streaming Tables, Materialized Views und temporären Views, nicht auf Sinks. Mit AUTO CDC FROM SNAPSHOT werden sie nicht unterstützt. Auf standalone Objekten, die Sie in Databricks SQL anlegen, funktioniert die Klausel ebenfalls, dort fehlt aber der Reiter für Datenqualität in der Oberfläche und Sie fragen das Event Log ab.

SQL
-- Ergebnisse je Expectation aus dem Event Log
SELECT
  origin.flow_name,
  details:flow_progress.data_quality.dropped_records AS verworfen,
  details:flow_progress.data_quality.expectations     AS ergebnisse
FROM event_log('<pipeline-id>')
WHERE event_type = 'flow_progress'
ORDER BY timestamp DESC;

Das Feld expectations enthält je Expectation Name, Dataset sowie passed_records und failed_records. Zwei Stolpersteine: Die Erfassung hängt an der Pipeline-Einstellung pipelines.metrics.flowTimeReporter.enabled, und bei Views können Metriken fehlen oder mehrfach auftreten, weil eine View nur bei Abfrage berechnet wird. Für Alarmierung nutzen Sie Event Hooks, also Python-Funktionen, die auf Pipeline-Ereignisse reagieren und einen Webhook ansteuern.

Plattformmittel statt Eigenbau. Delta setzt NOT NULL und CHECK durch, bei Verletzung scheitert die Transaktion. Primär-, Fremd- und Unique-Schlüssel sind rein informativ. Für Aktualität und Vollständigkeit gibt es Anomaly Detection in Unity Catalog, das die Commit-Historie einer Tabelle modelliert und die Zeilenzahl der letzten 24 Stunden gegen einen vorhergesagten Korridor prüft. Die Funktion ist auf Azure als Beta ausgewiesen und wird über die Vorschauseite freigeschaltet. Achten Sie auf den Zuschnitt: Aktualität bedeutet hier Commit-Zeitpunkt, nicht Ereigniszeit, denn die frühere ereignisbasierte Variante wird in der aktuellen Fassung nicht mehr unterstützt.

Contracts wirken anders, als der Name nahelegt. Ein erzwungener Contract mit not_null und check erzeugt auf Databricks in der Voreinstellung zuerst die Tabelle mitsamt Daten und setzt die Constraints danach per ALTER. Schlägt das fehl, hat die fehlerhafte Version die vorherige bereits ersetzt. Erst mit dem Flag use_materialization_v2 trennt der Adapter Erzeugung und Einfügen, und dann gelangen Verletzungen nicht in die Zieltabelle. Das Flag steht seit Version 1.10.0 auf false, und dbt Labs hat festgehalten, dass es wegen der verlorenen Atomarität nicht automatisch umgestellt wird.

YAML
models:
  - name: fct_deliveries
    config:
      materialized: table
      contract: {enforced: true}
    columns:
      - name: delivery_id
        data_type: string
        constraints:
          - type: not_null       # wird durchgesetzt
          - type: primary_key    # nur informativ
      - name: quantity
        data_type: int
        constraints:
          - type: check
            expression: "quantity > 0"

Eine Lücke im Adapter, nicht in der Plattform. Seit Juni 2026 können auch standalone Materialized Views Expectations tragen, Streaming Tables konnten es schon vorher. Die dokumentierte Konfigurationsliste von dbt-databricks für beide Materialisierungen kennt jedoch keine Expectations, sie umfasst Partitionierung, Clustering, Beschreibung, Tabelleneigenschaften, Tags, Zeitplan und Row Filter. Was dbt schreibt, lässt sich also nicht mit Expectations schützen, obwohl die Plattform es zuließe.

Aktualisierung und Prüfung laufen auseinander. Seit dbt-databricks 1.12 können Sie einer Materialized View den Zeitplan on_update mit at_most_every geben. Databricks verwaltet die Aktualisierung dann selbst, und dbt löst keine manuelle Aktualisierung mehr aus. Die Tabelle aktualisiert sich dann in dem Takt, den Sie dort hinterlegt haben, während die dbt-Tests nur laufen, wenn jemand dbt startet. Zwischen zwei dbt-Läufen liegen also beliebig viele ungeprüfte Aktualisierungen. Bei Streaming Tables kommt hinzu, dass der Adapter Änderungen an der Query nicht erkennt und CREATE OR REFRESH die geänderte Abfrage nur auf künftige Zeilen anwendet. Eine verschärfte Regel wirkt dort erst nach einem --full-refresh.

Welches Werkzeug die Transformationsstrecke überhaupt tragen sollte, behandeln wir getrennt in dbt oder Lakeflow pipelines auf Azure Databricks, die Einordnung der Schichten in Medallion ist kein Datenmodell.

Entscheidungshilfe

Zwei Fragen klären, wo die Prüfung liegt, fünf weitere entscheiden über die einzelne Regel. Die Empfehlungen in diesem Abschnitt stammen aus unseren Projekten, die Mechanik dahinter ist oben belegt.

Frage 1: Welches Werkzeug schreibt die Tabelle?

Das ist keine Präferenz, sondern eine Voraussetzung, und sie geht allem anderen vor. Schreibt eine Lakeflow-Pipeline die Tabelle, stehen Expectations zur Verfügung. Schreibt dbt sie, stehen sie nicht zur Verfügung, denn der Adapter kennt die Klausel nicht. dbt kann eine von Lakeflow geschriebene Tabelle hinterher testen, am Schreibvorgang aber nichts mehr ändern. Wer diese Frage überspringt, plant Regeln an einer Stelle ein, an der sie technisch nicht greifen können.

Frage 2: In welchem Takt erwarten die Abnehmer die Daten?

Aktualisierung im Stunden- oder Tagestakt bedeutet Batch, unabhängig davon, ob nächtlich voll geladen oder alle zwei Stunden inkrementell. Jeder Lauf endet und schafft damit einen Zeitpunkt, an dem geprüft werden kann. Minutentakt oder darunter bedeutet kontinuierliche Verarbeitung, in Lakeflow der continuous Pipeline Mode. Dann existiert dieser Zeitpunkt nicht, und eine nachgelagerte Prüfung hat nichts, woran sie sich hängen kann.

Was daraus folgt

Batch: die Datenqualität gehört zu dbt. Alle Regeln dort, Schlüssel, Referenzen, Wertebereiche, Typen, Spaltenlisten und Quellaktualität. Sie liegen versioniert im Repository, laufen im Deployment mit, und dbt build verhindert, dass eine fehlerhafte Zeile weiterwandert. Expectations kommen nur dazu, wenn Lakeflow die Ingestion ohnehin trägt, und dort ausschließlich für Regeln, die sich an einer einzelnen Zeile entscheiden.

Kontinuierliche Verarbeitung: die Datenqualität gehört zu den Expectations. Die Verarbeitung kennt keinen abgeschlossenen Lauf, zwischen zwei dbt-Ausführungen wird also nicht geprüft. Was sich an einer Menge entscheidet, verlagern Sie auf abgeleitete Batch-Modelle und prüfen es dort mit dbt. Ohne dbt im Haus übernehmen Validierungs-Datasets diese Rolle, mit dem Vorbehalt, dass sie nachgelagerte Tabellen nicht sperren.

Beide Werkzeuge im Einsatz: wer die Tabelle schreibt, prüft sie. In Lakeflow liegen nur Regeln, die sich an einer einzelnen Zeile entscheiden, in dbt alles, was mehr als eine Zeile ansieht. Bauen Sie unique und relationships nicht zusätzlich als Validierungs-Datasets nach, das ist die Doppelarbeit, die den Parallelbetrieb teuer macht. Ein Job mit Pipeline-Task und dbt-Task hält beides in einer Ausführung. Halten Sie die Zuordnung schriftlich fest, sonst entscheidet sie jeder neue Kollege neu.

Kein Werkzeug im Haus: Dann wählen Sie das Werkzeug nach der Transformationsstrecke aus, nicht nach der Datenqualität, und die Taktfrage aus Frage 2 beantwortet beides zugleich. Passt das gewählte Werkzeug zum Liefertakt, ist die verbleibende Prüflücke klein und mit den oben beschriebenen Mitteln zu schließen. Passt es nicht, ist das ein Einwand gegen die Werkzeugwahl selbst und gehört dort gelöst. Ein zweites Werkzeug allein wegen der Datenqualität einzuführen, löst das Problem nicht, sondern verdoppelt den Betrieb.

Fünf Fragen für die einzelne Prüfung

Prüfen Sie die Daten oder die Logik? Daten heißt Data Test in dbt oder Expectation in Lakeflow. Logik heißt Unit-Test gegen Mock-Daten, und der gehört in die Entwicklung und in die CI, nicht in den Produktionslauf. In dbt ist das ausgereift, in Lakeflow gibt es Unit-Tests bisher nur als Beta im Editor.

Entscheidet sich die Regel an einer Zeile oder an einer Menge? An einer Zeile: Expectation, wenn Lakeflow schreibt, sonst dbt. An einer Menge, also Eindeutigkeit, referentielle Integrität und Mengenvergleiche: immer dbt. Einer Expectation liegt im Moment der Auswertung nur eine Zeile vor, sie kann über eine Menge nichts aussagen.

Was soll mit der fehlerhaften Zeile geschehen, und brauchen Sie sie danach noch? Verwerfen und nie wieder ansehen: DROP ROW. Verwerfen, aber später untersuchen: warn mit dem Quarantäne-Muster. Nur melden und alles behalten: warn in Lakeflow oder store_failures_as in dbt. Die Reihenfolge ist wichtig, denn nach einem DROP ROW ist die Zeile weg.

Soll ein Fehler nachgelagerte Objekte aufhalten? In dbt erledigt das dbt build von allein, nachgelagerte Modelle werden übersprungen. In Lakeflow braucht es dafür zwei Pipelines und einen Job mit abhängigen Tasks. Ein Validierungs-Dataset allein sperrt nichts, das ist die häufigste Fehlannahme in diesem Muster.

Gibt es eine Toleranz? Schwellen kennt nur dbt, über warn_if, error_if und fail_calc. Eine Expectation kennt kein „ab zehn Verstößen“, sie entscheidet je Zeile. Wer eine Toleranz braucht und in Lakeflow arbeitet, wertet die Zähler aus dem Event Log aus und alarmiert über einen Event Hook selbst.

Drei Festlegungen aus der Praxis

Diese drei haben sich unabhängig vom Werkzeug bewährt. Verwenden Sie DROP ROW nur, wenn Sie die Zeile wirklich nicht mehr brauchen, sonst nehmen Sie warn mit dem Quarantäne-Muster. Setzen Sie error auf Schlüssel und Pflichtfelder und warn auf statistische Prüfungen, denn ein Setup, das nachts grundlos anschlägt, wird nach zwei Wochen weggeklickt. Und bauen Sie Aktualität und Vollständigkeit nicht selbst, sondern schalten Sie Anomaly Detection ein, solange Sie den Beta-Status akzeptieren können.

Sobald Sie in einer Landschaft ohne dbt anfangen, Validierungs-Datasets für Eindeutigkeit und Referenzen zu bauen, lohnt der Blick auf DQX aus den Databricks Labs. Das Framework kennt Prüfungen auf Zeilen-, Spalten- und Dataset-Ebene, lässt sich in YAML oder Python beschreiben, quarantäniert vor dem Schreiben und alarmiert über Slack, Teams oder Webhook. Der Vorbehalt ist deutlich: Das Projekt wird ausdrücklich zur Erkundung bereitgestellt, ohne Service Level Agreements, ohne Zusicherungen und ohne Support-Kanal.

Fazit

Zwei Merkmale genügen für die Zuordnung, und beide stehen fest, bevor die erste Regel geschrieben wird: Wer die Tabelle schreibt, prüft sie, und der Liefertakt entscheidet, ob eine nachgelagerte Prüfung überhaupt einen Zeitpunkt hat.

Für den laufenden Betrieb ergeben sich daraus drei Fälle. Bei Batch gehört die Datenqualität zu dbt, Expectations kommen nur dort dazu, wo Lakeflow ohnehin die Ingestion trägt. Bei kontinuierlicher Verarbeitung gehört sie zu den Expectations, und alles, was eine Menge betrifft, wandert auf abgeleitete Batch-Modelle. Laufen beide Werkzeuge, prüft jedes das, was es selbst schreibt: Zeilenregeln in Lakeflow, alles Übrige in dbt.

Datenqualität ist damit kein Kriterium für die Auswahl des Transformationswerkzeugs. Sie entscheidet nicht, welches Werkzeug Sie einführen, sondern nur, welche der beiden benannten Lücken Sie in Ihrer Strecke schließen müssen.

Stand: August 2026, geprüft gegen dbt Core 1.12, dbt-databricks 1.12, dbt_expectations 0.10.10 und Databricks Runtime 17.3 im Kanal CURRENT.

Falls Sie gerade vor genau so einer Implementierung stehen, kommen Sie gerne auf uns zu. Wir unterstützen Sie beim Aufbau moderner Data- und AI-Plattformen auf Azure Databricks.

Erstgespräch vereinbaren
Neue Beiträge per E-Mail

Ein bis zwei Mal im Monat ein neuer Beitrag zu Architektur, Modellierung und Betrieb von Data- & AI-Plattformen. Kein Vertrieb, jederzeit abbestellbar.

← Zurück zum Blog