Learning Platform
Глоссарий Troubleshooting
Урок 03.08 · 15 мин
Средний
DEFAULTMATERIALIZEDALIASEPHEMERALВыражения столбцов

DEFAULT, MATERIALIZED, ALIAS, EPHEMERAL

ClickHouse поддерживает четыре типа выражений столбцов, которые позволяют автоматически вычислять значения при INSERT или SELECT. Каждый тип имеет свой баланс между хранением, вычислениями и гибкостью.


Сравнительная таблица

Четыре типа выражений столбцов
ВыражениеТип выражения столбца: определяет поведение при INSERT и SELECT. Каждый тип решает свою задачу: DEFAULT -- значения по умолчанию, MATERIALIZED -- предвычисление, ALIAS -- виртуальные столбцы, EPHEMERAL -- входные данные для других столбцов.
Хранится на дискеХранится ли значение физически на диске в .bin файле. Хранимые столбцы занимают место, но не требуют вычислений при чтении. Нехранимые столбцы экономят диск, но требуют вычислений при каждом SELECT.
Когда вычисляетсяКогда вычисляется значение выражения. INSERT-time: значение вычисляется один раз при записи. SELECT-time: значение вычисляется при каждом запросе. Это ключевое различие между MATERIALIZED (INSERT-time) и ALIAS (SELECT-time).
В SELECT *Появляется ли столбец в результате SELECT *. DEFAULT -- единственный тип, который включается в SELECT * автоматически. MATERIALIZED, ALIAS и EPHEMERAL требуют явного указания имени столбца в SELECT.
Переопределяемый при INSERTМожно ли передать собственное значение при INSERT. DEFAULT позволяет переопределить значение. MATERIALIZED всегда вычисляет из выражения и игнорирует переданное значение. EPHEMERAL принимает значение, но не хранит его -- использует для вычисления других столбцов.
DEFAULTDEFAULT: стандартное значение по умолчанию. Если INSERT не предоставляет значение, вычисляется из выражения. Если предоставляет -- используется переданное значение. Хранится на диске, видно в SELECT *. Самый гибкий тип.
ДаDEFAULT хранится на диске в .bin файле. Занимает место, как обычный столбец. Сжимается кодеком таблицы.
INSERT (если не задано)DEFAULT вычисляется при INSERT, только если значение не предоставлено явно. Если INSERT передаёт значение для этого столбца, выражение по умолчанию игнорируется.
ДаDEFAULT столбцы включаются в SELECT * автоматически, как обычные столбцы. Это единственный тип выражения, для которого это верно.
ДаDEFAULT позволяет передать собственное значение при INSERT. Если INSERT содержит явное значение для этого столбца, оно используется вместо выражения по умолчанию.
MATERIALIZEDMATERIALIZED: предвычисленный столбец. Значение ВСЕГДА вычисляется из выражения при INSERT, даже если INSERT передаёт значение -- оно будет проигнорировано. Хранится на диске. Не видно в SELECT * -- нужно указать явно.
ДаMATERIALIZED хранится на диске в .bin файле. Занимает место, но экономит вычисления при каждом SELECT. Идеален для производных значений, которые часто читаются: дата из timestamp, хэш из строки.
INSERT (всегда)MATERIALIZED ВСЕГДА вычисляется при INSERT. Даже если INSERT явно передаёт значение для этого столбца, оно игнорируется. Выражение вычисляется из других столбцов строки.
Нет (нужен явный SELECT)MATERIALIZED НЕ включается в SELECT *. Чтобы прочитать MATERIALIZED столбец, нужно указать его имя явно: SELECT date, other_columns FROM table. Это защищает от случайного чтения вспомогательных столбцов.
Нет (игнорируется)MATERIALIZED НЕ позволяет переопределить значение при INSERT. Переданное значение будет проигнорировано. Столбец всегда вычисляется из выражения. Это гарантирует консистентность данных.
ALIASALIAS: виртуальный столбец. Не хранится на диске. Значение вычисляется при каждом SELECT. Экономит дисковое пространство, но тратит CPU при каждом запросе. Идеален для часто изменяющихся вычислений (возраст, текущая дата).
НетALIAS НЕ хранится на диске. Никакого .bin файла для этого столбца нет. Это экономит дисковое пространство и время INSERT, но каждый SELECT должен вычислять значение заново.
SELECT (каждый запрос)ALIAS вычисляется при каждом SELECT. Если выражение содержит now(), результат будет разным при каждом запросе. Это позволяет создавать 'живые' столбцы, всегда показывающие актуальное значение.
Нет (нужен явный SELECT)ALIAS НЕ включается в SELECT *. Нужно указать имя столбца явно: SELECT age_days FROM table. Это защищает от неожиданных вычислений при SELECT *.
НеприменимоALIAS -- нехранимый виртуальный столбец. Невозможно передать значение при INSERT, потому что столбец вычисляется при SELECT, а не при INSERT. INSERT для этого столбца не имеет смысла.
EPHEMERALEPHEMERAL: входной столбец, который потребляется при INSERT и не хранится. Используется как источник данных для вычисления DEFAULT или MATERIALIZED столбцов. После INSERT значение отбрасывается. Идеален для паттерна 'передай сырые данные -- сохрани производные'.
НетEPHEMERAL НЕ хранится на диске. Значение используется только при INSERT для вычисления других столбцов, затем отбрасывается. В .bin файле столбца нет.
INSERT (потребляется)EPHEMERAL существует только в момент INSERT. Значение передаётся в INSERT, используется для вычисления DEFAULT/MATERIALIZED столбцов, затем уничтожается. При SELECT столбец не существует.
НетEPHEMERAL НЕ включается в SELECT *. Столбец не хранится и не вычисляется при чтении. В SELECT он недоступен.
Да (потребляется)EPHEMERAL принимает значение при INSERT. Это его единственное назначение: получить данные от клиента и передать их в выражения других столбцов. Само значение не сохраняется.

DEFAULT: значение по умолчанию

Самый простой и гибкий тип. Если INSERT не предоставляет значение, используется выражение. Если предоставляет — переданное значение имеет приоритет.

CREATE TABLE logs (
    timestamp DateTime,
    level String DEFAULT 'INFO',
    message String
) ENGINE = MergeTree()
ORDER BY timestamp

-- INSERT без level → level = 'INFO'
INSERT INTO logs (timestamp, message) VALUES (now(), 'Server started')

-- INSERT с level → level = 'ERROR'
INSERT INTO logs VALUES (now(), 'ERROR', 'Disk full')

MATERIALIZED: предвычисление при INSERT

MATERIALIZED столбец всегда вычисляется из выражения. Даже если INSERT передаёт значение, оно игнорируется. Хранится на диске, но не появляется в SELECT *.

Типичный use case: предвычисленная дата для PARTITION BY:

CREATE TABLE events (
    timestamp DateTime,
    date Date MATERIALIZED toDate(timestamp),
    user_id UInt64,
    data String
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (user_id, timestamp)

Столбец date вычисляется из timestamp при каждом INSERT. Это экономит вычисления при чтении: вместо toDate(timestamp) в каждом запросе ClickHouse читает готовое значение из .bin файла.

-- SELECT * НЕ покажет date
SELECT * FROM events LIMIT 1
-- timestamp, user_id, data (без date)

-- Нужно указать явно
SELECT timestamp, date, user_id FROM events LIMIT 1
-- timestamp, date, user_id

ALIAS: виртуальный столбец

ALIAS не хранится на диске. Значение вычисляется при каждом SELECT. Это экономит хранение, но тратит CPU на каждый запрос.

Идеален для значений, которые зависят от текущего момента:

CREATE TABLE users (
    user_id UInt64,
    created_at DateTime,
    age_days UInt32 ALIAS dateDiff('day', created_at, now()),
    name String
) ENGINE = MergeTree()
ORDER BY user_id

Столбец age_days всегда возвращает актуальное число дней с момента регистрации. Он не занимает места на диске и не устаревает, потому что вычисляется заново при каждом запросе.

-- Нулевой расход диска
SELECT user_id, age_days FROM users WHERE user_id = 42
-- age_days вычисляется из created_at и now() в момент запроса

EPHEMERAL: входные данные для других столбцов

EPHEMERAL — самый экзотический тип. Столбец принимает значение при INSERT, передаёт его другим столбцам через их выражения, и затем уничтожается. Не хранится, не читается.

Паттерн: передать сырой JSON, извлечь поля:

CREATE TABLE parsed_events (
    raw_json String EPHEMERAL,
    name String DEFAULT JSONExtractString(raw_json, 'name'),
    age UInt8 DEFAULT JSONExtractUInt(raw_json, 'age'),
    city String DEFAULT JSONExtractString(raw_json, 'city')
) ENGINE = MergeTree()
ORDER BY name
-- INSERT передаёт raw_json → поля name, age, city извлекаются → raw_json отбрасывается
INSERT INTO parsed_events (raw_json)
VALUES ('{"name": "Alice", "age": 30, "city": "Moscow"}')

-- На диске хранятся только name, age, city. raw_json нигде нет.
SELECT * FROM parsed_events
-- name='Alice', age=30, city='Moscow'

Преимущество: клиент передаёт один blob, ClickHouse парсит его один раз при INSERT, хранит только нужные поля. JSON не занимает место на диске.


Ключевые выводы

  1. DEFAULT — значение по умолчанию. Хранится на диске, видно в SELECT *, можно переопределить при INSERT. Самый простой и распространённый тип.
  2. MATERIALIZED — предвычисление. Хранится на диске, но НЕ видно в SELECT * и НЕ переопределяемо. Экономит CPU при чтении за счёт хранения.
  3. ALIAS — виртуальный столбец. НЕ хранится на диске, вычисляется при каждом SELECT. Экономит диск за счёт CPU. Идеален для “живых” значений (возраст, текущая разница).
  4. EPHEMERAL — входной столбец. Принимает данные при INSERT, передаёт другим столбцам, затем уничтожается. Паттерн: парсинг JSON/сырых данных в типизированные поля.
  5. Баланс хранение vs вычисление: MATERIALIZED хранит и не считает при SELECT. ALIAS не хранит и считает при каждом SELECT. Выбирайте в зависимости от частоты чтения vs объёма данных.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. Инженер создаёт таблицу с MATERIALIZED столбцом: date Date MATERIALIZED toDate(timestamp). Что произойдёт, если INSERT явно передаст значение для столбца date?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 8