the-tinderbox/clickhouse-php-client
PHP 7.1+ ClickHouse HTTP client built on Guzzle. Configure single servers or clusters, pick random or specific hosts, and run queries per-cluster. Supports async SELECT and INSERT from local files via a simple Client/ServerProvider API.
## Getting Started
### Minimal Setup
To start using `the-tinderbox/clickhouse-php-client` in Laravel, install the package via Composer:
```bash
composer require the-tinderbox/clickhouse-php-client
Initialize a single-server client in your Laravel service provider or a dedicated ClickHouse facade:
use Tinderbox\Clickhouse\Server;
use Tinderbox\Clickhouse\ServerProvider;
use Tinderbox\Clickhouse\Client;
// In a service provider or facade
$server = new Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (new ServerProvider())->addServer($server);
$client = new Client($serverProvider);
// Example: Fetch data from ClickHouse
$result = $client->readOne('SELECT * FROM your_table LIMIT 10');
return $result->rows; // Returns an array of rows
Create a ClickHouse facade in app/Providers/AppServiceProvider.php for easy access:
use Illuminate\Support\Facades\Facade;
class ClickHouseFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'clickhouse.client';
}
}
Register the client in the same file:
public function register()
{
$this->app->singleton('clickhouse.client', function () {
$server = new Server(config('clickhouse.host'), config('clickhouse.port'), config('clickhouse.database'), config('clickhouse.user'), config('clickhouse.password'));
$serverProvider = (new ServerProvider())->addServer($server);
return new Client($serverProvider);
});
}
For high availability, configure a cluster in your config/clickhouse.php:
return [
'clusters' => [
'analytics' => [
[
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'analytics',
'user' => 'user',
'password' => 'pass',
],
[
'host' => '127.0.0.2',
'port' => '8123',
'database' => 'analytics',
'user' => 'user',
'password' => 'pass',
],
],
],
];
Use the cluster in your code:
$client->onCluster('analytics');
$result = $client->readOne('SELECT * FROM events');
Execute multiple queries asynchronously for performance:
list($events, $users) = $client->read([
['query' => 'SELECT * FROM events WHERE date = ?', ['2023-01-01']],
['query' => 'SELECT * FROM users WHERE status = ?', ['active']],
], 2); // Concurrency limit
Use local files for bulk inserts or temporary tables:
// Insert from CSV
$client->writeFiles('table', ['date', 'value'], [
new \Tinderbox\Clickhouse\Common\File(storage_path('app/export.csv')),
]);
// Query using a temp table
$result = $client->readOne(
'SELECT * FROM main_table WHERE id IN _temp_ids',
new \Tinderbox\Clickhouse\TempTable('_temp_ids', storage_path('app/ids.csv'), ['id' => 'UInt64'])
);
Extend Eloquent queries with ClickHouse:
// In a model trait or service
public function scopeInClickHouse($query, $column, $values)
{
$client = app('clickhouse.client');
$tempTable = new \Tinderbox\Clickhouse\TempTable('_filter', $values->path(), ['id' => 'UInt64']);
$result = $client->readOne("SELECT * FROM {$query->getTable()} WHERE {$column} IN _filter", $tempTable);
return $result->rows;
}
$client = new Client($serverProvider, [
'http_transport_options' => [
'middleware' => [
new \GuzzleHttp\Middleware::tap(function ($request) {
LaravelLog::debug('ClickHouse Request:', ['url' => (string) $request->getUri()]);
}),
],
],
]);
Avoid SELECT *: ClickHouse optimizes for columnar queries. Specify columns explicitly:
// Bad
$client->readOne('SELECT * FROM large_table');
// Good
$client->readOne('SELECT id, name FROM large_table');
Batch Async Queries: Limit concurrency ($concurrency in read()) to avoid overwhelming the server:
$client->read($queries, 5); // Max 5 concurrent requests
Deflate Compression: Disable if experiencing issues:
$client = new Client($serverProvider, [
'http_transport_options' => ['deflate' => false],
]);
Server Tags: Use tags to route queries to specific servers (e.g., for read/write separation):
$server->setTag('replica');
$client->usingServerWithTag('replica')->readOne('SELECT * FROM table');
Custom File Streams: Implement \Tinderbox\Clickhouse\Common\FileInterface for custom data sources (e.g., S3 files):
class S3File implements FileInterface {
public function getStream() { /* Return S3 stream */ }
public function getSize() { /* Return file size */ }
}
Query Logging: Log all queries via middleware:
$client = new Client($serverProvider, [
'query_logger' => function ($query, $params) {
\Log::info('ClickHouse Query', ['query' => $query, 'params' => $params]);
},
]);
| Error | Solution |
|---|---|
Connection refused |
Verify ClickHouse HTTP port (8123 by default) and firewall rules. |
Invalid query |
Use EXPLAIN in ClickHouse to debug syntax. |
File not found |
Ensure paths in TempTable are absolute and accessible by the server. |
Timeout |
Increase Guzzle timeout in http_transport_options: 'timeout' => 30. |
---
How can I help you explore Laravel packages today?