learning.lab
Ingestion & Other Engines· 23/33

Integration Engines

S3, MySQL, PostgreSQL, URL, File

Integration engines define a table backed by data that lives somewhere else — S3, another database, an HTTP endpoint, a local file — so you can query it with ClickHouse SQL without an ETL step to copy it in first. Every one of them shares the same formats covered in Insert & Export Formats for how the underlying bytes are read or written.

S3

Reads and writes objects (Parquet, CSV, JSONEachRow, etc.) directly in an S3 bucket, either as a permanent table or, more commonly, via the s3() table function for one-off queries against data that already lives in a lake:

-- permanent table
CREATE TABLE s3_events
ENGINE = S3('https://bucket.s3.amazonaws.com/events/*.parquet', 'Parquet');

-- or, no table definition needed at all
SELECT count() FROM s3('https://bucket.s3.amazonaws.com/events/*.parquet', 'Parquet');

MySQL / PostgreSQL

Proxies queries to a live external database — each SELECT against the ClickHouse table is translated and forwarded to the real MySQL or Postgres server, row by row over the network.

CREATE TABLE pg_countries
ENGINE = PostgreSQL('postgres:5432', 'ref', 'countries', 'admin', 'admin123');

This is convenient for occasional lookups against operational data without duplicating it, but it inherits the source database's performance characteristics for every query — running a billion-row analytical scan through a PostgreSQL engine table just turns it into a billion-row query against Postgres. For anything queried often or at volume, prefer a dictionary (for small reference data) or an actual ingestion pipeline into a real MergeTree table.

URL

Reads from or writes to an arbitrary HTTP(S) endpoint, using the same format machinery as everything else — useful for pulling a one-off feed or webhook payload into a query without writing a separate script.

SELECT * FROM url('https://example.com/rates.json', 'JSONEachRow');

File

Reads local files on the server's filesystem. Mostly a local development and testing convenience — production data almost never lives as loose files on a ClickHouse server's disk on purpose.

Why it exists
The common thread: integration engines trade query performance for skipping a separate copy/ETL step. That trade is worth it for exploration, bridging, and infrequent lookups. It stops being worth it the moment a query pattern becomes frequent or performance- sensitive — at that point, ingest the data into a real MergeTree table (or a dictionary, for small reference data) instead of querying the external system live, every time.
Production note
A MySQL or PostgreSQL engine table sends real load to that external database on every query. Treat it the same as any other client of that database — rate limits, connection pool exhaustion, and slow queries there are just as real a production risk as they would be from any other application.