To query a mysqldump file without importing it, use clickhouse local. It runs SQL directly on files from the command line, with no server to install. It's part of ClickHouse, so the same query scales to billions of rows when you outgrow your laptop.
Install it with clickhousectl:
curl https://clickhouse.com/cli | sh # install clickhousectl
clickhousectl local use latest # download ClickHouse and put it on your PATH
Then point it at the .sql file with the MySQLDump format and name the table you want:
clickhouse local -q "
SELECT * FROM file('shop.sql', MySQLDump)
SETTINGS input_format_mysql_dump_table_name = 'orders'
FORMAT PrettyCompact"
┌─id─┬─customer_id─┬─product─┬─revenue─┬─quantity─┐
1. │ 1 │ 1 │ widget │ 5 │ 1 │
2. │ 2 │ 2 │ gadget │ 6.01 │ 2 │
3. │ 3 │ 3 │ gizmo │ 7.02 │ 3 │
4. │ 4 │ 1 │ widget │ 8.03 │ 4 │
└────┴─────────────┴─────────┴─────────┴──────────┘
The MySQLDump format reads the INSERT statements straight out of the dump and exposes them as a table, so the file is queried in place with no restore step first.
A typical mysqldump file holds every table in a database, one CREATE TABLE plus one INSERT INTO per table. Before you query, it helps to see what's in there. The table names live on the INSERT INTO lines, so read the file as raw lines and pull them out:
clickhouse local -q "
SELECT extract(line, 'INSERT INTO .(\w+).') AS table_name
FROM file('shop.sql', LineAsString)
WHERE line LIKE 'INSERT INTO%'"
That tells you which names you can pass to input_format_mysql_dump_table_name below.
mysqldump writes the CREATE TABLE DDL right above the data, and clickhouse local reads it. DESCRIBE shows the column names and the types it mapped from the MySQL definitions, with no schema to declare yourself:
clickhouse local -q "
DESCRIBE file('shop.sql', MySQLDump)
SETTINGS input_format_mysql_dump_table_name = 'orders'
FORMAT PrettyCompact"
┌─name────────┬─type─────────────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
1. │ id │ Int32 │ │ │ │ │ │
2. │ customer_id │ Nullable(Int32) │ │ │ │ │ │
3. │ product │ Nullable(String) │ │ │ │ │ │
4. │ revenue │ Nullable(Decimal(10, 2)) │ │ │ │ │ │
5. │ quantity │ Nullable(Int32) │ │ │ │ │ │
└─────────────┴──────────────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
The MySQL int NOT NULL primary key became Int32, the nullable int columns became Nullable(Int32), and decimal(10,2) was preserved as Decimal(10, 2). Reading the rows is then a plain SELECT:
clickhouse local -q "
SELECT * FROM file('shop.sql', MySQLDump)
SETTINGS input_format_mysql_dump_table_name = 'orders'
FORMAT PrettyCompact"
┌─id─┬─customer_id─┬─product─┬─revenue─┬─quantity─┐
1. │ 1 │ 1 │ widget │ 5 │ 1 │
2. │ 2 │ 2 │ gadget │ 6.01 │ 2 │
3. │ 3 │ 3 │ gizmo │ 7.02 │ 3 │
4. │ 4 │ 1 │ widget │ 8.03 │ 4 │
└────┴─────────────┴─────────┴─────────┴──────────┘
input_format_mysql_dump_table_name is the whole trick. The dump may contain twenty tables; this setting tells clickhouse local which one's INSERT rows to return. Switch the value to read a different table out of the same file:
clickhouse local -q "
SELECT * FROM file('shop.sql', MySQLDump)
SETTINGS input_format_mysql_dump_table_name = 'customers'"
1 GB 2026-01-01
2 US 2026-01-02
3 DE 2026-01-03
Leave the setting off and clickhouse local reads the first table it finds in the file. That's a handy default for single-table dumps (the kind mysqldump db t produces), but with a multi-table dump you almost always want to be explicit:
clickhouse local -q "SELECT count() FROM file('shop.sql', MySQLDump)"
The setting applies to the whole query, so you read one table per query. To combine tables, query each into a Parquet or Native file once and join those, or load the dump into a ClickHouse server.
Because the dump is just a SQL source, the full ClickHouse dialect works on it — WHERE, GROUP BY, aggregates, window functions — with nothing loaded in between:
clickhouse local -q "
SELECT product, count() AS orders, round(sum(revenue), 2) AS revenue
FROM file('shop.sql', MySQLDump)
GROUP BY product
ORDER BY revenue DESC
SETTINGS input_format_mysql_dump_table_name = 'orders'
FORMAT PrettyCompact"
┌─product─┬─orders─┬─revenue─┐
1. │ widget │ 2 │ 13.03 │
2. │ gizmo │ 1 │ 7.02 │
3. │ gadget │ 1 │ 6.01 │
└─────────┴────────┴─────────┘
This is the everyday win: a colleague hands you a .sql dump, you answer a question about it in one command instead of restoring it into a database first. A .sql.gz dump works the same way. clickhouse local detects the .gz extension and decompresses on the fly, so you never unzip anything (querying compressed files).
The dump is plain text, so reading it means parsing SQL on every run, with no pre-built table behind it. Even so, parsing is the only cost. On a single-table dump of 2,000,000 rows (events_large.sql, ~64 MB of INSERT text generated by the example folder below), a full GROUP BY country with sum and avg over every row runs in:
clickhouse local -q "
SELECT country, count() AS events, round(sum(revenue), 2) AS revenue, round(avg(quantity), 3) AS avg_qty
FROM file('events_large.sql', MySQLDump)
GROUP BY country
ORDER BY revenue DESC
LIMIT 5
SETTINGS input_format_mysql_dump_table_name = 'events'
FORMAT PrettyCompact"
┌─country─┬─events─┬─────revenue─┬─avg_qty─┐
1. │ IN │ 200674 │ 50256630.75 │ 2.997 │
2. │ CA │ 200217 │ 50087310.66 │ 2.996 │
3. │ BR │ 200349 │ 50075129.05 │ 2.997 │
4. │ NL │ 200017 │ 50053869.17 │ 2.999 │
5. │ AU │ 200001 │ 50030477.09 │ 2.999 │
└─────────┴────────┴─────────────┴─────────┘
~0.35 seconds, best of three with a warm OS page cache, on an Apple M4 Pro laptop (14 cores, 24 GB RAM; clickhouse local 26.6.1.117). That includes parsing the whole dump from text on every run. If you'll query the data more than once, convert the table to Parquet once with INTO OUTFILE 'events.parquet' FORMAT Parquet and read that instead. Parquet is columnar and typed, so repeat scans get faster again. See how to query a Parquet file.
The SELECT ... GROUP BY you ran on a dump file is the same SQL you'd run on a ClickHouse server, or in ClickHouse Cloud. When the data outgrows a laptop, you swap file('shop.sql', MySQLDump) for a table name and the rest of the query stays put. You prototype against the dump on your machine and ship the identical logic to production.
The complete, runnable example lives here. It has generate.sh (builds a two-table shop.sql dump and the 2M-row events_large.sql perf dump, both in real mysqldump layout), run.sh (every command above), and expected_output.txt:
github.com/ClickHouse/examples → local-analytics/clickhouse-local-mysqldump
git clone https://github.com/ClickHouse/examples
cd examples/local-analytics/clickhouse-local-mysqldump
./generate.sh && ./run.sh