How to sync MySQL deletes to BigQuery▾

Learn

How to sync MySQL deletes to BigQuery

Why scheduled exports and timestamp-based syncs miss deleted rows, and how log-based CDC applies MySQL deletes to BigQuery while keeping a history of them.

A common surprise with MySQL to BigQuery syncs: rows deleted in MySQL are still in BigQuery weeks later. Here's why, and how to fix it.

Why deletes go missing

Incremental syncs usually copy rows whose updated_at is newer than the last run. A deleted row has no updated_at: it's simply gone, so the query never returns it and BigQuery keeps the old copy. Workarounds like soft-delete columns or periodic full reloads add work and cost.

Capture deletes from the binary log

MySQL's binary log records every delete with the row's primary key and values. A log-based CDC pipeline reads that event and:

  • removes the row from the up-to-date BigQuery table, so it matches MySQL, and
  • records the delete (_ds_op = 'd') in the change history, so you can still see that the row existed and when it was removed.

Querying deleted rows

SELECT id, _ds_ingested_at AS deleted_at
FROM `your-project.analytics_changelog.orders`
WHERE _ds_op = 'd'
ORDER BY _ds_ingested_at DESC;

With Quayen, deletes are handled automatically for every table; see table layout.