There are three real ways to do this, and the right one depends less on your data volume than on who is going to maintain it at 2am. Here's the honest comparison.
Moving the data once is easy. mysqldump, convert, bq load, done in an afternoon. Keeping it moving is the actual project: schema changes break loads, full refreshes get slower every month, and the tables that grow fastest are usually logs nobody queries.
The second underestimate is the read side. Whatever tool you choose, the extract runs against a server that is also serving your application. A full refresh is a long sequential scan over your largest tables, and it holds nothing back out of politeness. Most teams get away with it for months, then schedule it at 3am after the first bad night.
CDC via the binlog avoids the repeated scans, but raises the bar on access: ROW-format binlog, sufficient retention, a replication user, a spare server id. On managed or shared hosting, that's frequently just not available — which is what pushes people back to full refreshes.
All three work. They differ in what they cost you — in money, in maintenance, and in load on the database your customers are using right now.
Export tables to CSV or Parquet, load them into BigQuery on a cron.
Datastream, Debezium or similar read the binlog and stream changes into BigQuery.
BeQuery maintains an isolated, verified PostgreSQL copy of the MySQL database. Query it directly, or run your dump-and-load against the copy instead of the live server.
Read-only MySQL credentials, host and port. BeQuery connects, discovers your tables and clones them into an isolated PostgreSQL schema that only your team can reach.
Each sync rebuilds the copy and verifies it — row counts are checked against the source, so you know the data is complete rather than hoping it is. Production only ever sees a read.
Most people stop here: the clone is a real PostgreSQL database with a SQL editor, ready-made insights and BI connections. If you specifically need BigQuery, export the tables you care about from the clone and load them with bq load — the extract now runs against the copy, not your shop.
Run the export-and-load step on your own cron, after the sync completes. Because it reads the clone, it can run as often and as heavily as you like without a single query reaching production.
Worth asking before you build anything. A warehouse is the right tool for some of these situations and overkill for the rest.
Type edge cases, almost every time. MySQL's '0000-00-00' dates aren't valid timestamps anywhere else, unsigned bigints overflow signed targets, and zero-length strings versus NULL flip meaning between engines. BeQuery's type mapper deals with these when it clones, which is one class of failure you stop debugging.
Not today. Sync is scheduled — nightly through to roughly every minute depending on plan. Binlog-based CDC is on the roadmap and gated on the source database granting replication access, which is exactly the constraint that makes DIY CDC hard in the first place.
No, and we'd rather say so plainly. BeQuery clones your store's MySQL database into an isolated, verified PostgreSQL copy. There is no one-click push into BigQuery. What BeQuery removes is the hard part — pulling data out of a live shop safely and keeping it fresh — after which loading into BigQuery is an ordinary export-and-load step against a copy that nobody depends on.
You can, and for a small shop it may be fine. The catch is that every full refresh reads your production tables while customers are shopping, and the tables that grow fastest are usually tracking and log tables you don't want in a warehouse anyway. Extracting from a copy means a heavy read can never turn into a slow checkout.
As fresh as your sync schedule — nightly on the lower plans, hourly and faster on the higher ones. For a warehouse used for reporting, nightly is usually what people land on regardless of what the tool supports.
Free tier, no credit card, read-only access. Production is never written to — and you can explore the demo store before connecting anything.