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.
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.
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.