ClickHouse Native PHP Client
ClickHouse Native PHP Client
ClickHouse Native PHP Client
Tip: smi2/phpclickhouse
composer require smi2/phpclickhouse
Gotcha: Connection Setup
$client = new ClickHouseDB\Client(['localhost:8123']);
$client->database('default');
Tip: Select Query
$statement = $client->select('SELECT * FROM events WHERE date = ?', ['2024-01-01']);
$rows = $statement->rows();
Gotcha: Insert Data
$client->insert('events', [
[1, 'page_view', '2024-01-01'],
[2, 'click', '2024-01-01'],
], ['id', 'event', 'date']);
Tip: Async Insert
$client->settings()->max_execution_time(30);
Gotcha: Error Handling
try {
$client->ping();
} catch (\Exception $e) {
// Connection failed
}
Tip: Order of Columns in ORDER BY Matters Massively
ClickHouse's primary key is defined by ORDER BY. Put high-cardinality columns first for better data skipping. ORDER BY (timestamp, user_id) is very different from ORDER BY (user_id, timestamp) in query performance.
Tip: Use LowCardinality for Enum-Like Strings
Strings like status, country, browser benefit from LowCardinality(String) — it's stored as a dictionary internally, reducing storage 10x and speeding up scans.
Gotcha: Mutations Are Heavy
ALTER TABLE ... UPDATE and DELETE in ClickHouse create new parts instead of modifying in place. A single mutation on a large table can take hours and block merges. Design for append-only from day one.
Senior Insight
The native ClickHouse PHP client (smi2/phpclickhouse) communicates over HTTP, not TCP. This makes it simple to set up — no extensions needed. I use it in Laravel for scheduled reporting tasks that query ClickHouse directly. The streaming response mode is excellent for large result sets: instead of loading millions of rows into memory, it yields each row as it arrives. For ETL pipelines that move data between PostgreSQL and ClickHouse, this memory efficiency is essential.
Source: ClickHouse Blog (https://clickhouse.com/blog), Altinity Blog (https://altinity.com/blog), Altinity Knowledge Base (https://kb.altinity.com/)