Move tables and data from a ParadeDB-backed Postgres instance into a native ClickHouse cluster using SQL exports, CSV loads, and type mapping.
ClickHouse offers column-oriented storage and massive parallel reads, making large analytical queries faster than ParadeDB’s row-oriented Postgres base.
Regular tables, materialized views, and indexes migrate with CSV export. Extensions, triggers, and functions require manual rewrites or are unsupported.
Use the \COPY
or COPY
command with CSV
format and HEADER
. Disable compression to avoid CPU overhead during extraction.
\COPY Customers TO '/tmp/customers.csv' WITH (FORMAT CSV, HEADER);
\COPY Orders TO '/tmp/orders.csv' WITH (FORMAT CSV, HEADER);
INTEGER → Int32, BIGINT → Int64, TEXT/VARCHAR → String, TIMESTAMP → DateTime64(3), NUMERIC → Decimal(18,4). No direct array or JSON support—use String or nested tables.
CREATE TABLE Customers (
id UInt32,
name String,
email String,
created_at DateTime64(3)
) ENGINE = MergeTree
ORDER BY id;
CREATE TABLE Orders (
id UInt32,
customer_id UInt32,
order_date DateTime64(3),
total_amount Decimal(18,4)
) ENGINE = MergeTree
ORDER BY (customer_id, order_date);
Use clickhouse-client --query
with FORMAT CSV
piped from cat
for each table.
cat /tmp/customers.csv | clickhouse-client --query="INSERT INTO Customers FORMAT CSVWithNames"
Compare row counts and aggregate checksums.
-- Postgres
SELECT COUNT(*) FROM Customers;
-- ClickHouse
SELECT COUNT(*) FROM Customers;
1) Lock ParadeDB writes. 2) Export final delta. 3) Load into ClickHouse. 4) Validate. 5) Redirect application reads.
Skipping type mapping validations and ignoring time zone differences cause silent data issues. Always check destination column definitions.
No direct index migration. Recreate indexes as ClickHouse primary keys or skip if MergeTree ordering covers the query pattern.
Minimal downtime if you export a final delta after locking writes. Reads can stay on ParadeDB until ClickHouse is ready.