Clickhouse and the open source modern data stack

Clickhouse and the open source modern data stack

What is Clickhouse?

Clickhouse is an open-source (24.9k ⭐) “column-oriented” database. Column-oriented (or “columnar”), refers to how data is organized in the database. Here’s a good comparison of “row-oriented” vs. “column-oriented” databases. Columnar databases are faster than their row-oriented counterparts for analytical queries (e.g. counting the # of events per day over billions of events). Clickhouse is particularly fast.

Clickhouse was open sourced (Apache 2) in June 2016. Clickhouse, Inc. formed a company around the technology in 2021 and raised $250M in October 2021 to build a cloud product for Clickhouse. Altinity is the OG in Clickhouse cloud hosting and we can’t recommend them enough. It will be interesting to watch what cloud hosting products are built around Clickhouse as the adoption picks up.

We choose Clickhouse when building Luabase because of its speed and have grown to ♥️ it. Here’s a public notebook with all the data and SQL we cover below.

Who’s using it?

Clickhouse has been used at companies like Uber, Comcast, eBay, and Cisco for years, mostly for log analytics. We’re now seeing startups (e.g. Tinybird, Posthog, Logtail) adopting Clickhouse in their product because it’s open source, has amazing performance, and doesn’t tie you to an insanely expensive cloud service (looking at you BigQuery). Due to the ubiquity of SQL, it’s also easier to find developers to work on the product and integrate it with other tools (e.g. Metabase). We choose Clickhouse at Luabase for these same reasons and think it’ll become the de facto choice when you need an open source, blazing fast database.

Prerequisites

The rest of this post won’t make much sense if you don’t know SQL. I recommend DataCamp if you’re interested in learning. If you want to run some of the code yourself, set up Clickhouse on your machine. We’ve also loaded the data to Luabase.

Show me some code

Many people have written a good deal about Clickhouse’s performance on billions of rows of data, so we’re going to instead focus on some of the features that make it good for analytics, specifically:

  • Getting data into Clickhouse
  • Standard SQL goodness
    • Filtering, grouping, and sorting data
    • Manipulating data
    • Date functions
  • Some not-so-standard SQL functions
    • Progressively defining columns
    • Ability to pivot data
    • JSON functions
  • The open-source modern data stack
  • Getting data out of Clickhouse

Getting data into Clickhouse

This is a strong point of Clickhouse. It provides many ways to get data into it without adding another tool to your stack. The simplest import path is hitting a CSV file (or even a Google Sheet) that’s publicly available on the internet. This won’t work for “big data”, but it’s a good way to test the technology out.

If you already have data in Postgres or MySQL, Clickhouse can materialize data from an entire database or import data based on a SQL statement against the source database.

For simplicity, we downloaded a CSV of all HackerNews posts that mention SQL and loaded it to Google Cloud Storage. You can download the file here or query it in Clickhouse like this:

with hn as (
	select * 
	from 
	url('https://storage.googleapis.com/luabase-public/hn.csv', CSVWithNames)
)

select 
*
from hn 
limit 5 
format Vertical

This is great for getting a quick peak at the data, but to avoid importing the data every time we want to run a query we’ll store it in a table. Here’s a  create table for it:

CREATE DATABASE hn
CREATE TABLE hn.content 
(
    `title` Nullable(String),
    `url` Nullable(String),
    `text` Nullable(String),
    `dead` Nullable(Bool),
    `by` String,
    `score` Nullable(Float64),
    `time` Nullable(Float64),
    `timestamp` DateTime,
    `type` Nullable(String),
    `id` Float64,
    `parent` Nullable(Float64),
    `descendants` Nullable(Float64),
    `ranking` Nullable(String),
    INDEX hn_content_title_idx `title` TYPE bloom_filter GRANULARITY 1,
    INDEX hn_content_type_idx `type` TYPE bloom_filter GRANULARITY 1,
    INDEX hn_content_score_idx `score` TYPE bloom_filter GRANULARITY 1
)
ENGINE = MergeTree()
PARTITION BY (toYYYYMM(`timestamp`))
PRIMARY KEY (`id`, `by`)
ORDER BY (`id`, `by`)
SETTINGS index_granularity = 8192

You can then insert the data.

insert into hn.content
select *
from (
	select * 
	from 
	url('https://storage.googleapis.com/luabase-public/hn.csv', CSVWithNames)
) as hn

If you want to skip the steps above, follow along in Luabase instead.

Standard SQL goodness

Filtering, grouping, sorting

You can do all the standard stuff you’d expect with SQL in Clickhouse. For example, let’s get the top 100 posts (by “score”) that include Postgres in the title

select *
from hn.content as c
where c.title ilike '%postgres%'
order by c.score desc
limit 100

Or a sum of all mentions for Postgres, MySQL, BigQuery, and Clickhouse by month

Postgres, MySQL, BigQuery, and Clickhouse mentions by month
with flavor as (
    select 
    "timestamp",
    date_trunc('month', "timestamp") as content_month,
    c."title",
    c."text",
    c."url",
    (
        case 
        when 
            c."text" ilike '%postgres%' or 
            c."title" ilike '%postgres%' then 1 
            else 0 
        end) 
    as "postgres",
    (
        case 
        when 
            c."text" ilike '%mysql%' or 
            c."title" ilike '%mysql%' then 1 
            else 0 
        end) 
    as "mysql",
    (
        case 
        when 
            c."text" ilike '%bigquery%' or 
            c."title" ilike '%bigquery%' then 1 
            else 0 
        end) 
    as "bigquery",
    (
        case 
        when 
            c."text" ilike '%clickhouse%' or 
            c."title" ilike '%clickhouse%' then 1 
            else 0 
        end) 
    as "clickhouse"
    from hn."content" as c
)
select 
content_month,
sum(postgres) as postgres,
sum(mysql) as mysql,
sum(bigquery) as bigquery,
sum(clickhouse) as clickhouse,
count() as "total"
from
flavor as f
group by content_month
order by content_month asc
-- limit 200

Just BigQuery and Clickhouse

BigQuery and Clickhouse mentions

Some not-so-standard SQL functions

There are a few additions to Clickhouse’s SQL dialect that are particularly useful and not commonly found in other dialects:

Progressively defining columns

You can use a column you alias (as) in the definition of a subsequent column

select
case when c.text ilike '%clickhouse%' then 1 else 0 end as contains_ch,
case when contains_ch = 1 and c.score > 10 then 1 else 0 end as contains_ch_high_score,
c.score,
substring(c.text, 1, 20) as substr_text

from hn."content" as c
order by contains_ch_high_score desc
limit 20
High-scoring Postgres mentions

Pivoting data

You can pivot data wit sumMap (link)

with hn as (
    select
    date_trunc('month', "timestamp") as content_month,
    c.score,
    case 
    when 
        (c."text" ilike '%bigquery%' or 
        c."title" ilike '%bigquery%') and 
        (c."text" ilike '%clickhouse%' or 
        c."title" ilike '%clickhouse%') then 'both'
    when
        (c."text" ilike '%bigquery%' or 
        c."title" ilike '%bigquery%')  then 'bq'
    when
        (c."text" ilike '%clickhouse%' or 
        c."title" ilike '%clickhouse%') then 'ch'
    else 'neither'
    end as "bq_or_ch"
    from hn."content" as c
)

select
content_month,
sumMap(map(bq_or_ch, score)) as sum_map_bq_or_ch,
ifNull(sum_map_bq_or_ch['both'], 0) as both,
ifNull(sum_map_bq_or_ch['bq'], 0) as bq,
ifNull(sum_map_bq_or_ch['ch'], 0) as ch
from hn as c
group by content_month
order by content_month desc
Pivoted results

Clickhouse also has extensive support for handling JSON. Clickhouse released an experimental JSON column type in 22.3. It’s not at the level of JSON support in Postgres, but it’s on a path towards it.

The open-source modern data stack

Clickhouse seems cool, but how does it fit in with the rest of the tools we've all grown to love?

dbt

Clickhouse, Inc. recently accepted ownership of the dbt plugin for clickhouse. It doesn't have support for all the bells and whistles of clickhouse (e.g. Live Views and more advanced Table Engines), but they're moving fast to improve it.

ETL

Most of the big players (Fivetran, Airbyte, Rudderstack, etc.) have relatively limited support for Clickhouse today. Our pick: Airbyte. It supports Clickhouse as both a source and destination. It also has support for all the sources you'd expect and since its open source, fits nicely with the ethos of Clickhouse.

Business Intelligence

As in ETL, there's limited support for Clickhouse, but Metabase was one of the first to add support and is also open source. Other more established players like ThoughSpot and Looker are working to add Clickhouse as customers demand it.

Your open-source data stack

  • ETL your data with Airbyte
  • Clickhouse as your data warehouse
  • dbt as your modeling layer
  • Metabase for business intelligence and dashboards

Getting data out of Clickhouse

Clickhouse offers many export formats including those you’d expect like JSON, CSV, Parquet, and Arrow. We’ve used them all at Luabase and they work just like you’d expect. There’s also built-in support for exporting to S3 or Google Cloud Storage.

The Ugly

Ok, Clickhouse is clearly amazing, but what aren't you telling me? This sounds too good to be true.

You're right. There are some rough edges you're going to need to deal with using Clickhouse. If you're used to just throwing BigQuery or Snowflake compute at your data engineering problems, you need to change your mindset when working with Clickhouse. It requires more thoughtful data modeling and more DevOps work than its commercial counterparts. JOIN's are also not nearly as performant as in other cloud data warehouses. There are features to overcome this weakness, but they require an amount of work you might not be willing to put in. If having a fully open source stack is paramount to your product and you're willing to put the work in, look no further than Clickhouse. But if you need a data warehouse that "just works", Clickhouse is not the best option. There are still too many rough edges to justify using it for basic analytics needs.

Subscribe to Luabase Blog

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe