Типы данных ClickHouse: String, UInt, DateTime, LowCardinality, JSON и Array

Типы данных в ClickHouse напрямую влияют на скорость чтения, размер таблицы и удобство запросов. В аналитической базе нельзя бездумно хранить все как String: дата должна быть датой, деньги — Decimal, небольшие справочники — LowCardinality, а Nullable стоит включать только там, где действительно нужен отдельный смысл NULL

Типы данных ClickHouse: String, UInt, DateTime, LowCardinality, JSON и Array: ключевой визуальный блок

Почему типы так важны

ClickHouse хранит данные по колонкам. Когда значения в колонке одного типа и хорошо повторяются, они эффективно сжимаются и быстро читаются. Если вместо чисел, дат и статусов везде лежат строки, база теряет часть преимуществ: сложнее фильтровать, хуже сжатие, больше преобразований в запросах

Числовые типы

ТипКогда использовать
UInt8, UInt16, UInt32, UInt64Счетчики, id без отрицательных значений, статусы
Int8Int64Числа, где возможны отрицательные значения
Float32, Float64Измерения, метрики, приблизительные значения
DecimalДеньги и точные десятичные значения

Не берите максимальный тип "на всякий случай". Если статус помещается в UInt8, не нужен UInt64. Чем точнее тип, тем лучше сжатие и меньше чтение

Строки и LowCardinality

String подходит для произвольных строк: URL, поисковый запрос, сообщение, внешний id. Но если значений немного и они повторяются, используйте LowCardinality(String). Примеры: страна, тип события, тариф, источник, статус

event_type LowCardinality(String),
country LowCardinality(String),
plan LowCardinality(String)

LowCardinality хранит словарь значений и компактные ссылки на него. Это особенно полезно для измерений в аналитике

Дата и время

  • Date — день без времени. Подходит для партиций, отчетов по дням, календарных фильтров.
  • Date32 — расширенный диапазон дат.
  • DateTime — дата и время с точностью до секунды.
  • DateTime64 — дата и время с долями секунды, например для логов и метрик.
event_date Date,
event_time DateTime,
request_time DateTime64(3)

Если точность миллисекунд не нужна, не ставьте DateTime64 по привычке. Более точный тип не всегда лучше: он может быть избыточным для отчетов по дням и часам

Nullable: включать осторожно

Nullable(T) нужен, когда отсутствие значения отличается от нуля, пустой строки или значения по умолчанию. Но Nullable добавляет служебные данные и усложняет некоторые операции. Если поле всегда известно или можно задать нормальное значение по умолчанию, Nullable не нужен

-- Уместно: дата первого платежа может быть неизвестна
first_payment_at Nullable(DateTime)
-- Часто не нужно: статус лучше хранить явным значением
status LowCardinality(String) DEFAULT 'unknown'

JSON, Array, Tuple и Nested

ClickHouse умеет работать с полуструктурированными данными, но выбор зависит от задачи. Если структура стабильная, лучше использовать обычные колонки. Если ключи действительно меняются от события к событию, можно рассмотреть тип JSON. Если у записи есть список тегов, подойдет Array(String)

tags Array(String),
payload JSON,
position Tuple(Float64, Float64)

Не путайте JSON как формат загрузки и JSON как тип колонки. Можно загружать строки в формате JSONEachRow, но это не значит, что каждая колонка должна быть типа JSON

Пример хорошей схемы событий

CREATE TABLE demo.pageviews
(
    event_date Date,
    event_time DateTime64(3),
    user_id UInt64,
    url String,
    source LowCardinality(String),
    status UInt16,
    duration_ms UInt32,
    revenue Decimal(12, 2),
    tags Array(String),
    payload JSON
)
ENGINE = MergeTree
ORDER BY (event_date, source, user_id);

Как посмотреть типы в таблице

DESCRIBE TABLE demo.pageviews;
SELECT name, type
FROM system.columns
WHERE database = 'demo' AND table = 'pageviews';

Шпаргалка выбора типов

ДанныеРекомендуемый тип
id пользователяUInt64
тип событияLowCardinality(String)
день отчетаDate
время событияDateTime или DateTime64
стоимость заказаDecimal(12, 2)
HTTP-статусUInt16
тегиArray(String)
динамические свойства событияJSON, если структура реально меняется

Как мигрировать от сырых строк к нормальным типам

В реальных проектах данные часто приходят из CSV, логов или внешнего API, где все выглядит как строка. Не обязательно сразу строить идеальную модель. Практичный путь — создать staging-таблицу для сырой загрузки, проверить качество данных, а затем переложить их в typed-таблицу через INSERT SELECT

CREATE TABLE demo.raw_events
(
    event_time String,
    user_id String,
    event_type String,
    amount String
)
ENGINE = MergeTree
ORDER BY tuple();
INSERT INTO demo.events
SELECT
    toDate(parseDateTimeBestEffort(event_time)) AS event_date,
    parseDateTimeBestEffort(event_time) AS event_time,
    toUInt64(user_id) AS user_id,
    event_type,
    toDecimal64(amount, 2) AS amount
FROM demo.raw_events;

Так проще отлавливать мусорные значения: пустые даты, нечисловые id, неожиданные суммы. После стабилизации пайплайна staging-таблица может остаться как буфер или исчезнуть, если загрузчик сразу пишет в правильные типы

Что еще влияет на выбор типов

Когда можно оставить поле строкой?

Строка нормальна для URL, внешнего идентификатора или сырого payload, который редко участвует в фильтрах. Но дата, статус, сумма и тип события почти всегда выигрывают от нормального типа; это особенно заметно, когда вы начнете писать отчеты с функциями ClickHouse

Что проверить перед созданием таблицы?

Посмотрите не только пример данных, но и будущие запросы: где будут WHERE, GROUP BY, JOIN, какие поля попадут в ORDER BY. Если этот этап пропустить, придется возвращаться к уроку CREATE TABLE в ClickHouse уже после ошибок

Когда JSON и Array лучше вынести в отдельную тему?

Когда внутри payload появляются массивы тегов, динамические свойства события или вложенные атрибуты. Для этого есть отдельный разбор JSON, Array и ARRAY JOIN в ClickHouse: там проще увидеть, где тип помогает, а где усложняет запросы

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x