Research insights

Validating a data migration: methods compared

Summary checks, table reconciliation, per-object reconciliation, parallel runs and formal proof: what each one proves, and what it misses

Ted Ghose, Co-founder and CTO

Ted Ghose

Co-founder and CTO

Novuz Inc. · · 16 min read

Executive summary

Every migration ends with the same question: does the new platform give the same numbers as the old one? Teams answer it in five main ways. Summary checks compare totals. Table reconciliation compares tables row by row. Per-object reconciliation runs each converted procedure or job and its original on the same inputs. Parallel runs keep both systems live and watch for differences. Formal methods try to prove two queries are equivalent for every possible input. Each method proves something different, and each misses something. Most failed validations come from using one method where another was needed, or from comparing the wrong inputs.

Key points

  • Totals can match while individual rows are wrong. Summary checks catch gross errors, not quiet ones.
  • Table reconciliation shows that a table differs, but not which converted procedure or job caused it.
  • Formal proof of query equivalence is impossible in general, because the problem is undecidable for arbitrary SQL. Research tools such as Cosette prove some cases and leave others unknown.

Recommended actions

  • Decide what “the numbers match” means in writing, with tolerances, before the first run.
  • Pin both sides to one input snapshot, and record its identity in every report.
  • Combine methods: cheap checks first, per-object reconciliation for the logic, and a short parallel run only for the domain being cut over.

What does validation have to prove?

That every object in scope gives the same output on the same input, and that anyone can check it. That sentence has four parts, and each can fail on its own.

“Every object in scope” needs an agreed list. “The same output” needs a defined comparison, with tolerances. “The same input” needs a frozen snapshot that both sides read. “Anyone can check it” needs evidence a person who did not do the work can read.

One limit belongs beside any validation claim. Matching the original shows equivalence on the tested inputs. It does not show that the original was right. Known defects carry over, and should be fixed afterwards as separate, logged changes.

Method. This note compares five families of validation, using the published documentation of the main platform tools (Databricks Lakebridge, Databricks Genie Migrate, Snowflake SnowConvert AI) and the research literature on proving query equivalence. It uses no Novuz customer data.

Method 1: summary checks

Summary checks compare row counts and totals between the old and new tables: how many rows, the sum of an amount column, the number of distinct customers.

They are fast and cheap, and they catch gross errors such as a missing load or a duplicated batch. They are also the method most likely to give false comfort. A join that assigns one customer’s balance to another keeps the row count exact. Two wrong rows can add up to the right total.

Proves
That the volume and the headline totals agree
Misses
Wrong rows with the right total, swapped values, rounding differences that cancel out
Use it for
A first pass on every table, and as a cheap gate before more expensive checks

Method 2: table reconciliation

Table reconciliation compares the old and new versions of a table more closely: the schema, a hash of every row, or row-by-row values matched on key columns.

Databricks’ free Lakebridge tool is a good example of this method. Its Reconcile module offers four report types. A schema report compares column names and data types. A row report compares a hash of each row and needs no join key. A data report compares row and column values using join columns, with mismatch detail per column. An all report runs the data and schema checks together.

Lakebridge’s documentation also shows where the method needs care. For Teradata, row-hash reports need a hash function the user installs. For BigQuery, some types cannot be compared exactly, and some lossy matches, such as a DATETIME column against a timestamp, can be reported as matches and should be checked by hand.

Snowflake’s SnowConvert AI offers a similar data validation step, run from its command line, with results written to Snowflake tables. Databricks’ documentation for Genie Migrate advises running the converted code and comparing results with the source.

Proves
That a table on the new platform holds the same rows and values as on the old one
Misses
Which procedure, package or job produced a difference, and why
Use it for
Data movement, and as evidence that the target tables match at cutover

Method 3: per-object reconciliation

Per-object reconciliation goes one level deeper. Instead of comparing the final tables, it runs each converted object (a procedure, a package, a script or a job) and its original on the same frozen inputs, and compares what each one produces.

This is what a migration of logic needs, because it ties every difference to the object that caused it. A failed check points to one procedure and one line, not to a table that thousands of objects touched.

It is also more work to set up. Each object needs inputs that exercise its risky branches, and each comparison needs agreed tolerances. The checks usually run in tiers, cheapest first, and stop an object at its first failure.

  • Schema: names, types, precision, scale and nullability of each output.
  • Row counts: per output table, and per partition or business date on large tables.
  • Column aggregates: sums, counts, distinct counts, minimums and maximums on numeric and key columns.
  • Rows: sampled rows matched on keys, or keyed row hashes where every row matters, such as ledgers and regulatory returns.
  • Business checks: the queries the business owner already trusts, run on both sides.

This is the method Novuz uses, stated so readers can weigh this note: every converted object gets a report marked pass, fail or review, on agreed inputs, with each miss listed by line.

Method 4: parallel running

In a parallel run, the old and new systems both run in production for a period, and someone compares their outputs as real data flows through.

Parallel runs catch problems no test data predicted, because they see real inputs. They are also the most expensive method. Every month of a parallel run means paying for two platforms and two teams. Without an agreed pass rule, they end when someone gets tired, not when the numbers are proven.

Parallel runs work best when they are short and narrow: one domain at a time, for as long as finance needs to close a period or two, after per-object reconciliation has already cleared the logic.

Proves
That the new system matches the old on real production inputs, for the period observed
Misses
Branches that real data did not exercise during the run
Use it for
The final weeks before each domain cuts over

Method 5: formal proof of query equivalence

The strongest possible check would prove that two queries give the same result for every possible input, not just the inputs tested. Researchers have worked on this for decades.

The best-known recent example is Cosette, from the University of Washington, presented at CIDR 2017. Cosette takes two SQL queries and returns “equivalent”, “inequivalent” or “unknown”. When the queries differ, it produces a counterexample input. When they match, it aims to produce a machine-checked proof.

Its authors are clear about the limits. Equivalence for arbitrary SQL queries is undecidable, so no tool can settle every case. Cosette did not yet handle string operations such as LIKE, ORDER BY or floating-point numbers, and some proofs needed human help: in one set of 23 equivalent query pairs, 17 were proven automatically.

Formal methods are valuable research and useful for checking query rewrites. They are not yet a practical way to validate thousands of procedures with loops, temporary tables and error handling. Migrations still rely on testing with well-chosen inputs.

How do the methods compare?

Most migrations need more than one. The table sets out what each proves and when it pays.

MethodWhat it provesWhat it missesCostBest use
Summary checksVolumes and totals agreeWrong rows with the right totalLowFirst pass on every table
Table reconciliationTables hold the same rows and valuesWhich object caused a differenceMediumData movement and cutover evidence
Per-object reconciliationEach converted object matches its original on the same inputsBranches the inputs did not exerciseMedium to highConverted logic: procedures, packages, jobs
Parallel runningThe new system matches on real production dataBranches real data did not hit during the runHighThe last weeks before each domain cuts over
Formal equivalence proofTwo queries match for every inputMost real procedures; undecidable in generalResearch-gradeChecking individual query rewrites

Why do validations fail?

In our reading of published guidance and our own experience, the same few mistakes recur.

  • Comparing two different days. If the source loads overnight between reads, every mismatch is noise. Pin both sides to one snapshot.
  • Normalizing away real differences. Trimming every string or rounding every decimal can hide real errors. Normalize only for documented, agreed differences, and show each rule in the report.
  • Ignoring type and collation rules. A DECIMAL that lands as a DOUBLE, or a case-insensitive comparison that becomes case-sensitive, changes results quietly.
  • Testing only easy objects. A validation that never runs the error path or the dynamic SQL proves nothing about them.
  • Defining success afterwards. Tolerances agreed after the first failure are negotiations, not tests.

What are the limits of this note?

Tool capabilities change. The descriptions of Lakebridge, SnowConvert AI and Genie Migrate come from their documentation as published in November 2026; check the current version before relying on them.

The comparison of methods is qualitative. We know of no public study that measures how often each method misses errors in real warehouse migrations.

Sources

  1. Databricks Labs, Lakebridge Reconcile guide
  2. Databricks Labs, Lakebridge overview
  3. Databricks, Convert SQL scripts and ETL pipelines with Genie Migrate
  4. Snowflake, SnowConvert AI data validation
  5. Chu, S., Wang, C., Weitz, K. and Cheung, A., “Cosette: An Automated Prover for SQL”, CIDR 2017

Next step

See a per-object reconciliation report before you talk to us, or send ten of your own objects for a free Convert 10 run with a report for each.

Last reviewed:

More questions

More questions buyers ask

What are the ways to validate a data migration?

Five: summary checks of counts and totals, table reconciliation, per-object reconciliation of each converted procedure or job on the same inputs, parallel running in production, and formal proof of query equivalence. Most migrations combine the first four.

Is matching row counts enough to validate a migration?

No. Totals can match while individual rows are wrong; a join that swaps two customers’ balances keeps the count exact. Use counts as a cheap first pass, then compare values and run each converted object on the same inputs.

Can query equivalence be proven automatically?

Only in some cases. Equivalence for arbitrary SQL is undecidable. Research tools such as Cosette (CIDR 2017) prove some pairs, find counterexamples for others and return unknown for the rest, and do not yet cover all SQL features.

Find out what your logic debt is costing you.

Every object counted, lineage, dead code and a fixed price in three business days. $3,000, credited.

Take the logic debt scorecard

Not sure which door? The scorecard takes ten minutes and tells you.

Scorecard