$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[March 13, 2024] ClickHouse

ClickHouse Laravel Package Setup

ClickHouse Laravel Package: Setup Tips

────────────────────────────────────────────────────────

ClickHouse Laravel Package: Setup Tips

Tip: Install the Package

composer require smi2/phpclickhouse

This is the most popular ClickHouse client for PHP.

Gotcha: No Official Laravel Package

Unlike PostgreSQL or MySQL, there's no official Laravel ClickHouse driver. The smi2/phpclickhouse package is community-maintained.

Tip: Service Provider

// config/app.php
'providers' => [
    Clickhouse\Laravel\ClickhouseServiceProvider::class,
],

Gotcha: Configuration

// config/clickhouse.php
return [
    'default' => 'default',
    'connections' => [
        'default' => [
            'host' => env('CLICKHOUSE_HOST', 'localhost'),
            'port' => env('CLICKHOUSE_PORT', 8123),
            'database' => env('CLICKHOUSE_DATABASE', 'default'),
            'username' => env('CLICKHOUSE_USERNAME', 'default'),
            'password' => env('CLICKHOUSE_PASSWORD', ''),
        ],
    ],
];

Tip: Direct Client Usage

use Clickhouse\Client;

$client = new Client(config('clickhouse.connections.default'));
$client->insert('page_views', [
    ['id' => 1, 'url' => '/home', 'created_at' => date('Y-m-d H:i:s')],
]);

Gotcha: No Eloquent Integration

ClickHouse doesn't have an Eloquent driver. Use the query builder or raw queries.

Tip: Service Wrapper

class ClickHouseService
{
    public function trackPageView(string $url, ?int $userId): void
    {
        $this->client->insert('page_views', [
            ['url' => $url, 'user_id' => $userId, 'created_at' => now()],
        ]);
    }
}

Wrap the client for clean Laravel integration.

Gotcha: Connection Timeout

$client->setTimeout(5);
$client->setConnectTimeOut(5);

Set timeouts to prevent hanging on slow queries.

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 ClickHouse Laravel package (smi2/phpclickhouse or theclickhouse/phpclickhouse-laravel) provides a fluent query builder but doesn't support Eloquent models directly. I create dedicated repository classes for ClickHouse queries that return plain arrays, not Eloquent models. The architectural pattern: Eloquent models for PostgreSQL/MySQL transactional data, repository classes for ClickHouse analytical data. This keeps the codebase explicit about which database each query targets.

Source: ClickHouse Blog (https://clickhouse.com/blog), Altinity Blog (https://altinity.com/blog), Altinity Knowledge Base (https://kb.altinity.com/)

────────────────────────────────────────────────────────
<-- back to posts