Skip to main content

How To Move Data from MySQL to Apache Iceberg and Querying with Trino

7 min read

How To Move Data from MySQL to Apache Iceberg and Querying with Trino cover

Introduction​

MySQL is built to serve your application, not to answer analysts. When dashboards and ad hoc queries start scanning order history or event tables on the production instance, they compete with the reads and writes your users are waiting on. Replicas help for a while, but they still give you a row store tuned for transactions, and every new reporting need puts more pressure on the same database.

A common fix is to land MySQL data in Apache Iceberg and point Trino at it. Iceberg keeps the data as open tables in object storage, and Trino gives your team fast, distributed SQL over those tables without touching MySQL at all. Because Iceberg is an open format, the same tables stay available to any other engine you add later.

OLake Go handles the replication part. It reads changes from MySQL and writes them into Iceberg tables in a format Trino can read. This guide walks through each step in OLake Go: you'll connect MySQL, replicate the data to Iceberg tables in the catalog of your choice, pick Trino as your query engine, choose which tables to ingest, run the sync, and then query the data in Trino.

Step 1: Set Up the Source and Destination​

The OLake Go docs explain how to set up MySQL and Iceberg, so follow the links below for each one. Pick the catalog you want to use and follow the link below to help you set it up. To see which engines work with which catalogs, check Compatibility with Query Engines.

When both connection tests pass, you can move on to the next step.

SourceSetup Guide
MySQLLink
DestinationCatalogLink
Apache IcebergHIVELink
RESTLink
NESSIELink
AWS GLUELink
JDBCLink
PolarisLink
BigLakeLink
LakekeeperLink
UnityLink
S3 tablesLink
HorizonLink

Step 2: Create a Job and Select the Query Engine​

In the left menu, go to Ingestion > Jobs.

OLake UI left sidebar with Ingestion > Jobs selected

Click + Create Job at the top right.

OLake UI Jobs page with the + Create Job button at the top right

On the Job Configuration page, give your job a name (for example, blog_job) and choose how often it should run from the Frequency dropdown. Then pick MySQL as the source connector and select the source you created in Step 1, and do the same for the Iceberg destination.

OLake Job Configuration page with job name, frequency, MySQL source and Iceberg destination

Step 2a: Select Query Engine​

Under Advanced Settings, open the Target Query Engines dropdown.

Target Query Engines dropdown under Advanced Settings in the OLake job configuration

Select Trino. You can pick more than one engine, but this guide uses Trino only.

Target Query Engines dropdown list with Trino in the options

Click Next and you'll be redirected to the Stream configuration page.

Step 3: Configure Streams​

The Streams page lists every table in your MySQL database. Check the box next to each table you want to copy, or use Sync all to select everything. The Iceberg DB field at the top shows the database name your tables will land in, and you can click the edit icon to change it.

Click a table name to open its settings on the right. On the Config tab, you can:

  • Pick a sync mode. Full Refresh + CDC copies all current rows first and then keeps copying new changes
  • Choose an Ingestion Mode. Upsert updates existing rows when they change, while Append adds every change as a new row
  • Turn on Normalization to store nested data as regular columns

The Schema tab shows the table's columns, and the Partitioning tab lets you group data by a column so queries run faster.

OLake Streams page with table selection and Config tab settings

Step 3a: Specify Iceberg Delete Mode​

When the ingestion mode is Upsert, you can choose which type of delete file OLake Go writes to Iceberg.

Open the Upsert Type dropdown and select the delete type you want: Equality, Positional, or Deletion.

Equality is by default selected for Trino. You can change the delete mode to the one you prefer via the drop-down.

OLake Upsert Type dropdown with Equality selected

When you're done, click Create Job at the bottom right. A confirmation shows that your job was created, and clicking Jobs takes you back to the main Jobs page.

Step 4: Run the Sync​

Your new job appears in the Active jobs tab. The Last Run status column shows whether each run is Running, Completed, or Failed.

OLake Active jobs tab showing the job with Last Run status Completed

The job will run at its next scheduled time. To start it now, click the three dots in the Actions column next to the Job ID and select Sync now.

OLake job Actions menu with the Sync now option

To see how each run went, open the same menu and select Job Logs & History. This page lists every run with its start time, runtime, and status.

OLake Job Logs & History page listing each run with start time, runtime and status

Click View logs next to any run to see its full log, including when MySQL CDC started, the total records read, and when the sync finished.

Once the sync finishes, the new Iceberg files show up in your S3 bucket.

Step 5: Query with Trino​

Connect Trino to your AWS Glue catalog by creating a catalog file at etc/catalog/<catalog-name>.properties:

properties
connector.name=iceberg
iceberg.catalog.type=glue
hive.metastore.glue.region=<region>
hive.metastore.glue.aws-access-key=<access-key>
hive.metastore.glue.aws-secret-key=<secret-key>
fs.native-s3.enabled=true
s3.region=<region>
s3.aws-access-key=<access-key>
s3.aws-secret-key=<secret-key>

Restart Trino to load the catalog, then open the Trino CLI:

bash
trino --catalog <catalog-name> --schema <namespace>

See the tables OLake Go created:

sql
SELECT * FROM <table> LIMIT 10;

Trino query output showing rows from the Iceberg table

Conclusion​

You now have MySQL tables flowing into Apache Iceberg on a schedule, with CDC keeping inserts, updates, and deletes in step, and Trino reading those tables straight from your catalog. Reporting and exploration move off the production database, so MySQL keeps serving the application while analysts write plain SQL against Iceberg.

The tables aren't locked to Trino either. Spark, Flink, DuckDB, ClickHouse, and other Iceberg-compatible engines can read the same data through the same catalog, so you can add engines without building another pipeline. Check the compatibility guide to see which engines support which catalogs and delete formats. Have questions? Join the OLake Slack community.

Next steps

Related posts