NoSQL в Clickhouse


Clickhouse колоночная база данных, это значит что данные в ней хранятся не как строки, а именно буквально как колонки (можно увидеть как каждая таблица физически разделяет данные на файлы по колонкам). Эта особенность отличает Clickhouse от классических SQL баз данных вроде PosgreSQL и MySQL.

Но в то же время отличия от Clickhouse от них не так уж существенны, особенно на первый взгляд: Фактически, изменив концепцию хранения данных, поменяв местами строки с коломаками, мы остались всё с теми же таблицами. Поэтому в Clickhouse используется SQL-подобный язык, который на 90% совпадает с диалектами традиционных реляционных СУБД.

При этом Кликхаус не так уж сильно похож на другие NoSQL решения, вроде MongoDB, где для хранения данных используются пары ключ-значения, представляющие собой что-то вроде JSON структуры.

Так что же, не вдаваясь в подробности внутренней реализации, можно думать о Clickhouse как о быстрой SQL базе данных, только без транзакций (что-то вроде Timescale в PosgreSQL)?

Но всё-таки есть некоторые возможности Кликхауса (они, честно говоря, не на поверхности), которые заставляют задуматься о нем не как о табличной SQL бд).

Одна из таких особенностей - это Nested структуры.

Этот тип данных представляет собой вложенную таблицу. В отличие от, например, хранения JSON данных в PosgreSQL эта таблица будет first-class структурой, т.е. поддерживать все операции, что и обычные таблицы. Также судя по всему эти данные также хранятся как точно так же, как и основные данные, в виде столбцов. Что ещё удивительнее, поддерживается больше одного уровня вложенности (как экспериментальная фича) хотя большой вопрос насколько это практично.

Одина эта единственная фича сильно отдаляет Кликхаус от традиционных SQL СУБД, и гораздо больше напоминает вышеупомянутые структуры key-value, где ключом будет значение в nested столбце, который ссылается на данные-таблицу.

Стоит также отметить, что судя по всему эта фича ещё довольно экспериментальная. Вставка в такие таблицы, с точки зрения документации достаточно загадочное действие: Предполагается, что вставлять в такие таблицы нужно из JSON-объектов, но вот беда - в моей текущей версии Кликхауса они не поддерживаются даже как экспериментальная функция.

После долгих страданий, всё же удалось найти решение - мы используем тип данных Map, который чем-то схож с JSON, однако поддерживает значения только одного типа. Обойти это ограничение можно, храня значения в String и преобразовывая перед непосредственной вставкой обратно в их родной тип (решение, вероятно, не очень по эффективности, зато рабочее).

WITH    
    _src_category_agg AS (
        SELECT 
            groupArray(map(
                'category_id'  , toString(category_id),
                'category_text', category_text
            )) AS nested_data
        FROM
            ...
SELECT 
    arrayMap(x -> toUInt64(x['category_id']), nested_data) AS category_ids,
    arrayMap(x -> x['category_text']        , nested_data) AS category_texts,
    ...
FROM 
    _src_category_agg

Сейчас можно предположить, что несмотря на внешнюю кажимость SQL базой данных, Clickhouse вероятно будет развивать NoSQL особенности, представляя собой своего рода гибрид между типичными реляционными БД и разного рода альтернативными решениями хранения данных.