Обычное представление
Параметризованное представление
system.columns нет информации о параметризованных представлениях.
Кроме того, запросы DESCRIBE работают только при указании параметров.
Materialized View
OR REPLACE и IF NOT EXISTS являются взаимоисключающими: их совместное использование вызывает синтаксическую ошибку.
CREATE OR REPLACE MATERIALIZED VIEW
CREATE OR REPLACE MATERIALIZED VIEW атомарно заменяет существующее materialized view и его внутреннюю таблицу хранения (если она есть). Для выполнения этой операции требуется движок базы данных Atomic или Replicated.
- Без предложения
TO: старая внутренняя таблица удаляется и создается новая. Существующие данные во внутренней таблице теряются, если не указанPOPULATE. - С предложением
TO: заменяется только определение представления; целевая таблица и ее данные не затрагиваются. - Совместимо с
REFRESH,ON CLUSTERи любыми параметрами движка.POPULATEподдерживается только в базах данныхAtomic— в базах данныхReplicatedон не допускается (см. примечание оPOPULATEниже). - Требуются привилегии
CREATE VIEWиDROP VIEW.
CREATE OR REPLACE MATERIALIZED VIEW поддерживается только для движков баз данных Atomic и Replicated. Для движка базы данных Ordinary это не поддерживается.TO [db].[table] необходимо указать ENGINE — движок таблицы для хранения данных.
При создании materialized view с TO [db].[table] также можно использовать POPULATE для дозагрузки целевой таблицы существующими исходными данными (целевая таблица может уже содержать данные; в этом случае дозагружаемые строки добавляются). POPULATE нельзя сочетать с REFRESH: refreshable materialized view заполняется при первом обновлении, поэтому POPULATE загрузил бы исходные данные дважды (вместо этого используйте EMPTY, чтобы пропустить первое обновление).
Materialized view работает следующим образом: при вставке данных в таблицу, указанную в SELECT, часть вставленных данных преобразуется этим запросом SELECT, а результат вставляется в представление.
В ClickHouse materialized view при вставке в целевую таблицу используют имена столбцов, а не их порядок. Если каких-то имён столбцов нет в результате запроса
SELECT, ClickHouse использует значение по умолчанию, даже если столбец не является Nullable. Надёжнее всего указывать псевдонимы для каждого столбца при использовании materialized view.В ClickHouse materialized view реализованы скорее как триггеры вставки. Если в запросе представления есть агрегация, она применяется только к пакету только что вставленных данных. Любые изменения существующих данных в исходной таблице (например, update, delete, drop partition и т. д.) не изменяют materialized view.В ClickHouse у materialized view нет детерминированного поведения в случае ошибок. Это означает, что блоки, которые уже были записаны, сохранятся в целевой таблице, а все блоки после ошибки — нет.По умолчанию, если запись в одно из представлений приводит к исключению, запрос INSERT завершается ошибкой. При этом нет гарантии, что к этому моменту блок уже попал в исходную таблицу — это зависит от момента срабатывания конвейера вставки, а не от ошибки представления. Повторите неудавшийся INSERT с дедупликацией вставки (insert_deduplicate, deduplicate_blocks_in_dependent_materialized_views), чтобы получить доставку exactly-once в исходную таблицу и все зависимые представления.Установка materialized_views_ignore_errors=true в запросе INSERT изменяет только отчётность об ошибках: каждая ошибка представления записывается как предупреждение, а запрос INSERT завершается успешно. Доставка в пункт назначения представления, завершившегося с ошибкой, будет частичной — блоки, обработанные до исключения, сохраняются, а проблемный блок и все последующие блоки отбрасываются из этого представления. Представления ниже по цепочке от этого пункта назначения видят только те блоки, которые действительно поступили, поэтому их доставка тоже частична. Соседние представления (и их нисходящие цепочки), которые не сгенерировали исключение, записываются полностью, а запись в исходную таблицу происходит как обычно. Поскольку INSERT сообщает об успехе, клиент не получает сигнала о сбое и автоматический повтор не запускается; используйте эту настройку только тогда, когда запись в исходную таблицу не должна блокироваться из-за проблем на стороне представлений (например, для таблиц system.*_log).Для таблиц system.*_log значение materialized_views_ignore_errors по умолчанию равно true.POPULATE, существующие данные исходной таблицы будут вставлены в представление при его создании. В противном случае представление содержит только данные, вставленные в исходную таблицу после создания представления.
Для обычного CREATE MATERIALIZED VIEW операция POPULATE по умолчанию атомарна (настройка materialized_views_populate_atomically = 1): представление подписывается на новые вставки в исходную таблицу, а снимок существующих данных создаётся одновременно с этим под кратковременной эксклюзивной блокировкой исходной таблицы. Поэтому каждая строка, вставленная одновременно с заполнением, доставляется в представление ровно один раз — без пропусков и дубликатов. Затем заполнение (которое может выполняться долго) читает закреплённый снимок, не удерживая блокировку.
Это атомарность локального пути вставки: эксклюзивная блокировка сериализуется только со вставками, которые получают блокировку хранилища этой исходной таблицы на том же сервере, поэтому гарантия exactly-once распространяется на вставки, поступающие через этот сервер. Это не гарантия для всего кластера — строки, вставленные в другую реплику источника ReplicatedMergeTree или через распределённый путь записи (например, в таблицу Distributed или через ON CLUSTER) одновременно с заполнением, находятся за пределами этой отсечки и всё ещё могут быть пропущены или продублированы.
Если заполнение завершается ошибкой — например, эксклюзивная блокировка занятой исходной таблицы не может быть получена за время lock_acquire_timeout или SELECT представления генерирует исключение при выполнении, — только что созданное представление удаляется, а запрос CREATE завершается ошибкой, не оставляя ничего из созданного, поэтому его можно просто повторить. Для формы TO [db].[table] этот откат удаляет только представление, но никогда не удаляет уже существующую целевую таблицу — однако строки, уже вставленные неудавшимся заполнением в целевую таблицу, остаются в ней, как и после неудавшегося INSERT ... SELECT в эту таблицу, поэтому повторный CREATE вставляет их снова. Если обратное заполнение должно быть точным, повторите операцию с очищенной или новой целевой таблицей либо используйте движок с дедупликацией, например ReplacingMergeTree.
Атомарность требует, чтобы исходная таблица поддерживала чтение закреплённого снимка на фиксированный момент времени — это семейство
MergeTree и Memory. Для любого другого источника (представления, Distributed, Merge, Buffer, семейства Log или таблицы не из базы данных Atomic) заполнение выполняется с устаревшим, неатомарным поведением (что фиксируется в журнале сервера): существующие данные считываются с отдельного, нескоординированного снимка, поэтому строки, вставленные во время заполнения, могут быть пропущены или продублированы. В таком случае создайте представление и выполните отдельный INSERT ... SELECT, если вам нужны точные данные. Установка materialized_views_populate_atomically = 0 принудительно включает это устаревшее поведение для всех источников.Атомарное заполнение применяется только к обычному CREATE MATERIALIZED VIEW. CREATE OR REPLACE / REPLACE MATERIALIZED VIEW ... POPULATE всегда используют устаревшее, неатомарное заполнение.POPULATE не поддерживается для баз данных Replicated (для переопределения используйте database_replicated_allow_heavy_create) и не поддерживается в ClickHouse Cloud. Если он включён с помощью этого переопределения, заполнение всегда будет устаревшим и неатомарным — неудавшееся заполнение нельзя было бы согласованно откатить на всех репликах.SELECT может содержать DISTINCT, GROUP BY, ORDER BY, LIMIT. Обратите внимание, что соответствующие преобразования выполняются независимо для каждого блока вставленных данных. Например, если задан GROUP BY, данные агрегируются во время вставки, но только в пределах одного пакета вставленных данных. Далее данные не агрегируются. Исключение — использование ENGINE, который сам выполняет агрегацию данных, например SummingMergeTree.
Если materialized view использует конструкцию TO [db.]name, можно выполнить DETACH представления, запустить ALTER для целевой таблицы, а затем ATTACH ранее отсоединённого (DETACH) представления.
Представления выглядят так же, как обычные таблицы. Например, они отображаются в результате запроса SHOW TABLES.
Чтобы удалить представление, используйте DROP VIEW. Хотя DROP TABLE тоже работает для VIEW.
Безопасность SQL
DEFINER и SQL SECURITY позволяют указать, от имени какого пользователя ClickHouse выполнять запрос, лежащий в основе представления.
SQL SECURITY имеет три допустимых значения: DEFINER, INVOKER или NONE. В секции DEFINER можно указать любого существующего пользователя или CURRENT_USER.
В следующей таблице показано, какие права требуются и какому пользователю, чтобы выполнять SELECT из представления.
Обратите внимание: независимо от выбранного режима безопасности SQL, в любом случае для чтения из представления по-прежнему требуется GRANT SELECT ON <view>.
SQL SECURITY NONE — устаревший параметр. Любой пользователь, имеющий права на создание представлений с SQL SECURITY NONE, сможет выполнять любые произвольные запросы.
Поэтому для создания представления с этим параметром требуется GRANT ALLOW SQL SECURITY NONE TO <user>.DEFINER/SQL SECURITY не указаны, результат зависит от настройки сервера ignore_empty_sql_security_in_create_view_query.
При значении по умолчанию true запрос сохраняется в исходном виде, а представление получает пустой тип безопасности SQL. Обычное представление при этом выполняется с разрешениями вызывающего пользователя, а для materialized view с явно указанной целевой таблицей проверки доступа к этой целевой таблице пропускаются: вставка в исходную таблицу не требует привилегии INSERT на целевую таблицу, а чтение из представления не требует привилегии SELECT на неё.
При значении false в определение представления при создании записываются следующие значения по умолчанию:
SQL SECURITY:INVOKERдля обычных представлений (настраивается черезdefault_normal_view_sql_security) иDEFINERдля materialized view (настраивается черезdefault_materialized_view_sql_security)DEFINER:CURRENT_USER(настраивается черезdefault_view_definer)
DEFINER/SQL SECURITY, сохраняет пустой тип безопасности SQL.
Чтобы изменить безопасность SQL для существующего представления, используйте
Примеры
Live View
Refreshable Materialized View
interval — последовательность простых интервалов:
REFRESH должно быть указано как минимум одно из EVERY, AFTER или DEPENDS ON. Просто REFRESH (без них) не допускается. REFRESH DEPENDS ON ... без EVERY/AFTER — это сокращение для REFRESH AFTER 0 SECOND DEPENDS ON ...; см. ниже раздел Refresh Dependencies.
Периодически выполняет соответствующий запрос и сохраняет его результат в таблице.
- Если указано
APPEND, при каждом обновлении в таблицу добавляются новые строки без удаления существующих. Вставка не является атомарной, как и в обычном запросеINSERT INTO ... SELECT. - В противном случае при каждом обновлении предыдущее содержимое таблицы атомарно заменяется.
- Нет insert trigger. Когда новые данные вставляются в таблицу, указанную в
SELECT, они не передаются автоматически в refreshable materialized view. Вместо этого данные вставляются только во время периодических или ручных обновлений. - Для запроса
SELECTнет ограничений. Допускаются табличные функции (например,url()), просмотры, UNION, JOIN.
Настройки в части запроса
REFRESH ... SETTINGS — это настройки обновления (например, refresh_retries), а не обычные настройки (например, max_threads). Обычные настройки можно указать с помощью SETTINGS в конце запроса.Расписание обновления
RANDOMIZE FOR случайным образом смещает время каждого обновления, например:
REFRESH EVERY 1 MINUTE занимает 2 минуты, оно будет обновляться раз в 2 минуты. Если затем оно начнёт выполняться быстрее и обновляться за 10 секунд, оно снова вернётся к обновлению раз в минуту. (В частности, оно не будет обновляться каждые 10 секунд, чтобы наверстать пропущенные обновления — никакой очереди таких обновлений не существует.)
Обычно первое обновление запускается сразу после создания materialized view: время с момента последнего обновления равно бесконечности, поэтому по любому расписанию обновление должно начаться прямо сейчас. Если указано EMPTY, это начальное обновление пропускается, а первое обновление произойдёт в следующий момент по расписанию; например, для EVERY 1 HOUR первое обновление произойдёт в конце текущего часа.
В базе данных Replicated
APPEND координацию можно отключить с помощью SETTINGS all_replicas = 1. В этом случае реплики выполняют обновления независимо друг от друга. Тогда ReplicatedMergeTree не требуется.
В режиме без APPEND поддерживается только координируемое обновление. Для нескоординированного обновления используйте базу данных Atomic и запрос CREATE ... ON CLUSTER, чтобы создать refreshable materialized view на всех репликах.
Координация выполняется через Keeper. Путь znode определяется настройкой сервера default_replica_path.
Зависимости при обновлении
DEPENDS ON синхронизирует обновление разных таблиц:
DEPENDS ON работает только между refreshable materialized view. В частности, если представление-зависимость использует TO <table>, обязательно указывайте имя представления, а не таблицы. Если список DEPENDS ON содержит обычную таблицу, не-refreshable представление или опечатку, представление никогда не будет обновляться и в system.view_refreshes будет иметь состояние MissingDependencies. Зависимости можно изменить или удалить с помощью ALTER, см. Изменение параметров обновления.Использование DEPENDS ON для согласованной задержки распространения
REFRESH EVERY с одинаковым периодом, зависимость действует в каждом временном интервале.
Например, предположим, что представления X и Y используют REFRESH EVERY 1 HOUR, а Y читает из выходной таблицы X. Без зависимостей Y обычно будет видеть данные X из обновления за предыдущий час. С DEPENDS ON X обновление Y в 11:00 начнется только после завершения обновления X в 11:00.
Использование DEPENDS ON для батчевой потоковой обработки
REFRESH EVERY не используется, зависимое представление X обновляется, когда все его зависимости обновились хотя бы один раз с момента последнего обновления X. REFRESH AFTER T добавляет задержку: зависимое представление начнет обновляться через T после завершения обновления зависимости.
Циклические зависимости допустимы и полезны. Рассмотрим такой граф refreshable materialized views:
- X берет батч строк из некоторого потока и помещает их в таблицу.
- Затем Y и Z читают из этой таблицы, выполняют разные агрегации и добавляют результаты в другие таблицы.
- После полной обработки батча X берет следующий батч, и цикл повторяется.
SYSTEM REFRESH VIEW, а не только один раз после создания представлений.
Настройки обновления
refresh_retries- Сколько раз повторять попытку, если запрос обновления завершается исключением. Если все повторные попытки завершаются неудачей, обновление пропускается до следующего запланированного времени. 0 означает отсутствие повторных попыток, -1 — бесконечное число повторных попыток. Значение по умолчанию: 2.refresh_retry_initial_backoff_ms- Задержка перед первой повторной попыткой, еслиrefresh_retriesне равно нулю. При каждой следующей повторной попытке задержка удваивается, вплоть доrefresh_retry_max_backoff_ms. Значение по умолчанию: 100 мс.refresh_retry_max_backoff_ms- Ограничение на экспоненциальный рост задержки между попытками обновления. Значение по умолчанию: 60000 мс (1 минута).all_replicas- В Replicated database сAPPENDопределяет, будут ли все реплики обновляться независимо или в каждый запланированный момент обновление будет выполнять только одна реплика. Не может быть изменено после создания представления. Значение по умолчанию:false.
Изменение параметров обновления
ALTER TABLE ... MODIFY REFRESH:
EVERY или AFTER) обязательно: этот оператор всегда заменяет все параметры обновления — расписание, RANDOMIZE FOR, DEPENDS ON и настройки обновления — на указанные в нём. Всё, что опущено, сбрасывается к значению по умолчанию (настройки) или удаляется (зависимости, рандомизация).
-
Чтобы изменить только настройки обновления (например,
refresh_retries), заново укажите текущее расписание: -
ALTER TABLE ... MODIFY SETTING refresh_retries = ...не поддерживается для materialized view; нужно использоватьMODIFY REFRESH. -
Добавлять или удалять
APPENDне поддерживается. -
Настройку
all_replicasнельзя изменить после создания.
Другие операции
system.view_refreshes. В частности, в ней содержатся прогресс обновления (если оно выполняется), время последнего и следующего обновления, а также сообщение об исключении, если обновление завершилось ошибкой.
Чтобы вручную остановить, запустить, инициировать или отменить обновления, используйте SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW.
Чтобы дождаться завершения обновления, используйте SYSTEM WAIT VIEW. Это особенно полезно, если нужно дождаться первого обновления после создания представления.
Интересный факт: запросу обновления разрешено читать из обновляемого представления, при этом он видит версию данных до обновления. Это означает, что вы можете реализовать игру «Жизнь» Конвея: https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==
Оконное представление
MATERIALIZED VIEW. Для хранения промежуточных данных оконному представлению требуется внутреннее хранилище. Его можно указать с помощью предложения INNER ENGINE; по умолчанию оконное представление использует AggregatingMergeTree в качестве внутреннего движка.
При создании оконного представления без TO [db].[table] необходимо указать ENGINE — движок таблицы для хранения данных.
Функции временных окон
АТРИБУТЫ ВРЕМЕНИ
time_attr функции временного окна в столбец таблицы или используя функцию now(). Следующий запрос создает оконное представление с временем обработки.
WATERMARK.
Оконное представление поддерживает три стратегии водяной метки:
STRICTLY_ASCENDING: Выдаёт водяную метку, равную максимальной наблюдаемой на текущий момент временной метке. Строки, у которых временная метка меньше максимальной, не считаются опоздавшими.ASCENDING: Выдаёт водяную метку, равную максимальной наблюдаемой на текущий момент временной метке минус 1. Строки, у которых временная метка равна максимальной или меньше неё, не считаются опоздавшими.BOUNDED: WATERMARK=INTERVAL. Выдаёт водяные метки, равные максимальной наблюдаемой временной метке минус указанная задержка.
WATERMARK:
ALLOWED_LATENESS=INTERVAL. Пример обработки опоздавших событий:
SELECT запрос, указанный в оконном представлении, с помощью оператора ALTER TABLE ... MODIFY QUERY. Структура данных, получающаяся в результате выполнения нового SELECT запроса, должна быть такой же, как у исходного SELECT запроса, как с предложением TO [db.]name, так и без него. Обратите внимание, что данные в текущем окне будут потеряны, поскольку промежуточное состояние нельзя использовать повторно.
Мониторинг новых окон
TO для вывода результатов в таблицу.
LIMIT, чтобы задать количество обновлений, которые нужно получить до завершения запроса. Предложение EVENTS позволяет использовать сокращённую форму запроса WATCH: вместо результата запроса вы получите только последнюю водяную метку запроса.
Настройки
window_view_clean_interval: Интервал очистки оконного представления в секундах для удаления устаревших данных. Система сохраняет окна, которые ещё не были полностью активированы в соответствии с системным временем или конфигурациейWATERMARK, а остальные данные удаляются.window_view_heartbeat_interval: Интервал heartbeat-сигнала в секундах, показывающий, что watch-запрос активен.wait_for_window_view_fire_signal_timeout: Тайм-аут ожидания сигнала срабатывания оконного представления при обработке по времени события.
Пример
data, и структура этой таблицы такова:
WATCH получаем результаты.
data,
WATCH должен вывести результаты в следующем виде:
TO.
*window_view*).
Использование оконного представления
- Мониторинг: Агрегируйте и вычисляйте метрики по журналам во времени и выводите результаты в целевую таблицу. Панель мониторинга может использовать целевую таблицу в качестве исходной.
- Анализ: Автоматически агрегируйте и предварительно обрабатывайте данные в пределах временного окна. Это может быть полезно при анализе большого количества журналов. Предварительная обработка устраняет повторяющиеся вычисления в нескольких запросах и уменьшает задержку выполнения запросов.
- Блог: Работа с временными рядами в ClickHouse
- Блог: Создание решения для обсервабилити на ClickHouse — часть 2 — трейсы
Временные представления
- Срок жизни сеанса Временное представление существует только в рамках текущего сеанса. По завершении сеанса оно удаляется автоматически.
- Без базы данных Для временного представления нельзя указывать имя базы данных. Оно существует вне баз данных (в пространстве имен сеанса).
-
Не реплицируется / без ON CLUSTER
Временные объекты локальны для сеанса и не могут создаваться с
ON CLUSTER. - Разрешение имен Если временный объект (таблица или представление) имеет то же имя, что и постоянный объект, и запрос ссылается на это имя без указания базы данных, используется временный объект.
-
Логический объект (без хранения)
Временное представление хранит только текст своего
SELECT(внутри используется хранилищеView). Оно не сохраняет данные и не поддерживаетINSERT. -
Предложение ENGINE
Указывать
ENGINEне требуется; если указатьENGINE = View, оно будет проигнорировано / обработано как то же логическое представление. -
Безопасность / привилегии
Для создания временного представления требуется привилегия
CREATE TEMPORARY VIEW, которая неявно предоставляется черезCREATE VIEW. -
SHOW CREATE
Используйте
SHOW CREATE TEMPORARY VIEW view_name;, чтобы вывести DDL временного представления.
Синтаксис
OR REPLACE не поддерживается для временных представлений (по аналогии с временными таблицами). Если вам нужно «заменить» временное представление, удалите его и создайте заново.
Примеры
Недопустимые варианты / ограничения
CREATE OR REPLACE TEMPORARY VIEW ...→ не допускается (используйтеDROP+CREATE).CREATE TEMPORARY MATERIALIZED VIEW .../WINDOW VIEW→ не допускается.CREATE TEMPORARY VIEW db.view AS ...→ не допускается (без указания базы данных).CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...→ не допускается (временные объекты локальны для сеанса).POPULATE,REFRESH,TO [db.table], внутренние движки и все специфичные для MV секции → не применимы к временным представлениям.
Примечания о распределённых запросах
Memory), их данные могут передаваться на удалённые серверы при выполнении распределённого запроса — так же, как и в случае временных таблиц.