CREATE VIEW
Создает новое представление. Представления бывают обычными, материализованными, обновляемыми материализованными и оконными.
Обычный вид
Синтаксис:
Обычные представления не хранят данные. При каждом обращении к представлению оно просто выполняет чтение из другой таблицы. Другими словами, обычное представление — это не что иное, как сохранённый запрос. При чтении из представления этот сохранённый запрос используется как подзапрос в предложении FROM.
В качестве примера предположим, что вы создали представление:
и составили запрос:
Этот запрос полностью эквивалентен подзапросу:
Параметризованное представление
Параметризованные представления похожи на обычные представления, но могут создаваться с параметрами, которые не подставляются (не разрешаются) сразу. Эти представления можно использовать с табличными функциями, где имя представления выступает в роли имени функции, а значения параметров передаются как её аргументы.
Приведённый выше запрос создаёт представление, которое можно использовать как табличную функцию, подставляя параметры, как показано ниже.
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.
Примеры:
Здесь приведено пошаговое руководство по использованию materialized views.
Materialized views хранят данные, преобразованные соответствующим запросом SELECT.
При создании materialized view без TO [db].[table] необходимо указать ENGINE – движок таблицы для хранения данных.
При создании materialized view с TO [db].[table] нельзя дополнительно использовать POPULATE.
Materialized view реализовано следующим образом: при вставке данных в таблицу, указанную в SELECT, часть вставляемых данных преобразуется этим запросом SELECT, и результат вставляется в представление.
Materialized views в ClickHouse при вставке в целевую таблицу используют имена столбцов, а не порядок столбцов. Если некоторые имена столбцов отсутствуют в результате запроса SELECT, ClickHouse использует значение по умолчанию, даже если столбец не является Nullable. Безопасной практикой будет добавлять псевдонимы для каждого столбца при использовании materialized views.
Materialized views в ClickHouse больше напоминают триггеры на вставку. Если в запросе представления есть некоторая агрегация, она применяется только к пакету вновь вставленных данных. Любые изменения существующих данных исходной таблицы (такие как update, delete, drop partition и т.п.) не изменяют materialized view.
Materialized views в ClickHouse не имеют детерминированного поведения в случае ошибок. Это означает, что блоки, которые уже были записаны, будут сохранены в целевой таблице, но все блоки после ошибки записаны не будут.
По умолчанию, если отправка в одно из представлений приводит к исключению, запрос 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 TABLE ... AS SELECT ... . В противном случае запрос содержит только данные, вставленные в таблицу после создания представления. Мы не рекомендуем использовать POPULATE, поскольку данные, вставленные в таблицу во время создания представления, не будут вставлены в него.
Учитывая, что POPULATE работает как CREATE TABLE ... AS SELECT ..., у него есть ограничения:
- Он не поддерживается с реплицируемыми базами данных (Replicated database).
- Он не поддерживается в ClickHouse Cloud.
Вместо этого можно использовать отдельный запрос INSERT ... SELECT.
Запрос SELECT может содержать DISTINCT, GROUP BY, ORDER BY, LIMIT. Учтите, что соответствующие преобразования выполняются независимо для каждого блока вставляемых данных. Например, если задан GROUP BY, данные агрегируются во время вставки, но только в пределах одного пакета вставляемых данных. Данные не будут дополнительно агрегироваться. Исключение — использование ENGINE, который самостоятельно выполняет агрегацию данных, например SummingMergeTree.
Если materialized view использует конструкцию TO [db.]name, вы можете выполнить DETACH представления, запустить ALTER для целевой таблицы, а затем ATTACH ранее отсоединенное (DETACH) представление.
Обратите внимание, что на materialized view влияет настройка optimize_on_insert. Данные объединяются перед вставкой в представление.
Представления выглядят так же, как обычные таблицы. Например, они перечислены в результате запроса SHOW TABLES.
Чтобы удалить представление, используйте DROP VIEW. Хотя DROP TABLE также работает для представлений (VIEW).
SQL-безопасность
DEFINER и SQL SECURITY позволяют указать, под каким пользователем ClickHouse будет выполняться базовый запрос представления.
SQL SECURITY может принимать три допустимых значения: DEFINER, INVOKER или NONE. В предложении DEFINER вы можете указать любого существующего пользователя или CURRENT_USER.
В следующей таблице объясняется, какие права требуются какому пользователю, чтобы выполнять запросы к представлению.
Обратите внимание, что независимо от варианта SQL-безопасности во всех случаях по‑прежнему требуется иметь GRANT SELECT ON <view>, чтобы читать из него.
| Опция SQL-безопасности | Представление | Материализованное представление |
|---|---|---|
DEFINER alice | У пользователя alice должна быть привилегия SELECT на исходную таблицу представления. | У пользователя alice должны быть привилегии SELECT на исходную таблицу представления и INSERT на целевую таблицу представления. |
INVOKER | У пользователя должна быть привилегия SELECT на исходную таблицу представления. | SQL SECURITY INVOKER не может быть указан для материализованных представлений. |
NONE | - | - |
SQL SECURITY NONE — устаревшая опция. Любой пользователь с правами на создание представлений с SQL SECURITY NONE сможет выполнять произвольные запросы.
Поэтому для создания представления с этой опцией требуется иметь GRANT ALLOW SQL SECURITY NONE TO <user>.
Если DEFINER / SQL SECURITY не указаны, используются значения по умолчанию:
SQL SECURITY:INVOKERдля обычных представлений иDEFINERдля материализованных представлений (настраивается параметрами)DEFINER:CURRENT_USER(настраивается параметрами)
Если представление подключено (ATTACH) без указания DEFINER / SQL SECURITY, то значением по умолчанию будет SQL SECURITY NONE для материализованного представления и SQL SECURITY INVOKER для обычного представления.
Чтобы изменить настройки SQL-безопасности для существующего представления, используйте
Примеры
Live View
Данная возможность признана устаревшей и будет удалена в будущем.
Для вашего удобства старая документация доступна здесь
Refreshable materialized VIEW
где interval — последовательность простых интервалов:
В предложении REFRESH должно быть указано хотя бы одно из EVERY, AFTER или DEPENDS ON. Использование REFRESH без них не допускается. REFRESH DEPENDS ON ... без EVERY/AFTER — это сокращение для REFRESH AFTER 0 SECOND DEPENDS ON ...; см. Зависимости обновления ниже.
Периодически выполняет соответствующий запрос и сохраняет его результат в таблице.
- Если указано
APPEND, при каждом обновлении в таблицу добавляются строки без удаления существующих. Вставка при этом не является атомарной, как и в обычном запросеINSERT INTO ... SELECT. - В противном случае каждое обновление атомарно заменяет предыдущее содержимое таблицы.
Отличия от обычных необновляемых materialized VIEW:
- Нет триггера на вставку. Когда новые данные вставляются в таблицу, указанную в
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 первое обновление произойдёт в конце текущего часа.
В реплицируемой БД
Если обновляемое материализованное представление находится в реплицируемой базе данных, реплики координируют работу таким образом, что в каждый момент по расписанию обновление выполняет только одна реплика. Требуется движок таблиц ReplicatedMergeTree, чтобы все реплики видели данные, полученные в результате обновления.
В режиме APPEND координацию можно отключить с помощью SETTINGS all_replicas = 1. Тогда реплики выполняют обновления независимо друг от друга и ReplicatedMergeTree не требуется.
В режиме, отличном от APPEND, поддерживается только координируемое обновление. Для некоординируемого варианта используйте базу данных Atomic и запрос CREATE ... ON CLUSTER для создания обновляемых материализованных представлений на всех репликах.
Координация выполняется через Keeper. Путь znode задаётся настройкой сервера default_replica_path.
Зависимости при обновлении
DEPENDS ON синхронизирует обновление разных таблиц:
Обновление зависимого представления начнется только после того, как завершатся обновления всех представлений, от которых оно зависит.
Чтобы запускать обновление сразу после обновления другого представления:
Или, эквивалентно:
DEPENDS ON работает только между refreshable materialized view. В частности, если зависимое представление использует TO <table>, обязательно указывайте имя представления, а не таблицы. Если список DEPENDS ON содержит обычную таблицу, непериодически обновляемое представление или опечатку, представление никогда не будет обновляться и будет иметь состояние MissingDependencies в system.view_refreshes. Зависимости можно изменить или удалить с помощью 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 берет следующий батч, и цикл повторяется.
Полный пример:
Более длинные цепочки тоже работают.
Однако это хорошо работает только при включенной координации обновления, то есть когда представления находятся в базе данных Replicated или Shared. Без координации перезапуск сервера разрывает цикл, поэтому после каждого перезапуска приходится вручную выполнять 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- В реплицируемой базе данных сAPPENDопределяет, будут ли все реплики обновляться независимо или в каждый запланированный момент обновление будет выполнять только одна реплика. Не может быть изменён после создания представления. По умолчанию:false.
Изменение параметров обновления
Чтобы изменить параметры обновления существующего refreshable materialized view, используйте 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нельзя изменить после создания.
Примеры:
Другие операции
Состояние всех refreshable materialized view доступно в таблице system.view_refreshes. В частности, она содержит прогресс обновления (если оно выполняется), время последнего и следующего обновления, сообщение об исключении, если обновление завершилось с ошибкой.
Чтобы вручную остановить, запустить, инициировать или отменить обновление, используйте SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW.
Чтобы дождаться завершения обновления, используйте SYSTEM WAIT VIEW. Это, в частности, полезно для ожидания первоначального обновления после создания VIEW.
Интересный факт: запрос обновления может читать из обновляемого VIEW, видя версию данных до обновления. Это означает, что вы можете реализовать игру «Жизнь» Конвея: https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==
Оконное представление
Это экспериментальная функция, которая в будущих релизах может изменяться без сохранения обратной совместимости. Включите поддержку оконных представлений и запроса WATCH, используя настройку allow_experimental_window_view. Выполните команду set allow_experimental_window_view = 1.
Оконное представление может агрегировать данные по временным окнам и выводить результаты, когда окно готово сработать. Оно сохраняет частичные результаты агрегации во внутренней (или указанной) таблице для уменьшения задержки и может отправлять результат обработки в указанную таблицу или отправлять уведомления с использованием запроса WATCH.
Создание оконного представления аналогично созданию MATERIALIZED VIEW. Оконному представлению требуется внутренний движок хранения для сохранения промежуточных данных. Внутреннее хранилище может быть задано с помощью клаузы INNER ENGINE, при этом оконное представление по умолчанию будет использовать AggregatingMergeTree в качестве внутреннего движка.
При создании оконного представления без TO [db].[table] необходимо указать ENGINE — движок таблицы для хранения данных.
Функции временных окон
Функции временных окон используются для получения нижней и верхней границ окна для записей. Оконное представление должно использоваться совместно с функцией временного окна.
ВРЕМЕННЫЕ АТРИБУТЫ
Оконное представление поддерживает обработку по времени обработки (processing time) и по времени события (event time).
Время обработки позволяет оконному представлению формировать результаты на основе локального времени машины и используется по умолчанию. Это наиболее простой способ интерпретации времени, но он не обеспечивает детерминизм. Атрибут времени обработки может быть задан путём установки time_attr функции временного окна равным столбцу таблицы или с помощью функции now(). Следующий запрос создаёт оконное представление с использованием времени обработки.
Время события (event time) — это время, когда каждое событие произошло на устройстве, которое его сгенерировало. Это время обычно встраивается в записи в момент их формирования. Обработка по времени события позволяет получать согласованные результаты даже в случае событий, пришедших не по порядку или с опозданием. Window view поддерживает обработку по времени события с использованием синтаксиса WATERMARK.
Window view предоставляет три стратегии формирования watermark:
STRICTLY_ASCENDING: выдаёт watermark, равный максимальной наблюдавшейся на данный момент метке времени. Строки с меткой времени, меньшей, чем максимальная метка времени, не считаются опоздавшими.ASCENDING: выдаёт watermark, равный максимальной наблюдавшейся на данный момент метке времени минус 1. Строки с меткой времени, меньшей или равной максимальной метке времени, не считаются опоздавшими.BOUNDED: WATERMARK=INTERVAL. Выдаёт watermark, который равен максимальной наблюдавшейся метке времени за вычетом указанной задержки.
Следующие запросы являются примерами создания Window view с WATERMARK:
По умолчанию окно срабатывает при поступлении watermark, а элементы, которые поступают позже watermark, отбрасываются. Оконное представление поддерживает обработку поздних событий через параметр ALLOWED_LATENESS=INTERVAL. Пример обработки таких опоздавших событий:
Обратите внимание, что элементы, выдаваемые при позднем срабатывании, следует рассматривать как обновлённые результаты предыдущего вычисления. Вместо срабатывания в конце окон представление окна будет срабатывать сразу при поступлении запоздалого события. В результате для одного и того же окна может быть получено несколько выходных результатов. Пользователям необходимо учитывать эти дублирующиеся результаты или удалять дубликаты.
Вы можете изменить запрос SELECT, который был указан в оконном представлении, с помощью оператора ALTER TABLE ... MODIFY QUERY. Структура данных, формируемая новым запросом SELECT, должна совпадать со структурой данных исходного запроса SELECT — как при указании клаузы TO [db.]name, так и без неё. Обратите внимание, что данные в текущем окне будут потеряны, поскольку промежуточное состояние не может быть повторно использовано.
Мониторинг новых окон
Оконное представление поддерживает запрос WATCH, который позволяет отслеживать изменения, а также синтаксис TO для вывода результатов в таблицу.
LIMIT может быть указан для задания количества обновлений, которые нужно получить перед завершением запроса. Предложение EVENTS можно использовать для получения сокращённой формы запроса WATCH, при которой вместо результата запроса вы будете получать только последнюю водяную метку (watermark) запроса.
Settings
window_view_clean_interval: Интервал очистки оконного представления в секундах для освобождения устаревших данных. Система будет сохранять окна, которые ещё не были полностью сработаны в соответствии с системным временем или конфигурациейWATERMARK, а остальные данные будут удалены.window_view_heartbeat_interval: Интервал heartbeat в секундах, указывающий, что watch‑запрос активен.wait_for_window_view_fire_signal_timeout: Таймаут ожидания сигнала срабатывания оконного представления при обработке по времени события.
Example
Предположим, нам нужно посчитать количество click‑логов за каждые 10 секунд в таблице логов data, структура которой следующая:
Сначала создадим оконное представление с фиксированным (tumbling) временным окном продолжительностью 10 секунд:
Затем используем запрос WATCH, чтобы получить результаты.
Когда логи вставляются в таблицу data,
Запрос WATCH должен выводить результаты следующим образом:
Также можно направить результат в другую таблицу, используя синтаксис TO.
Дополнительные примеры можно найти среди stateful-тестов ClickHouse (там они называются *window_view*).
Использование Window View
Window View полезен в следующих сценариях:
- Мониторинг: Агрегировать и вычислять метрики по логам во времени, выводя результаты в целевую таблицу. Панель мониторинга может использовать целевую таблицу в качестве источника данных.
- Аналитика: Автоматически агрегировать и предварительно обрабатывать данные во временном окне. Это может быть полезно при анализе больших объемов логов. Предварительная обработка устраняет повторные вычисления в нескольких запросах и снижает задержку выполнения запросов.
Связанные материалы
- Блог: Работа с временными рядами в ClickHouse
- Блог: Построение системы обсервабилити с помощью ClickHouse — часть 2. Трейсы
Временные представления
ClickHouse поддерживает временные представления со следующими характеристиками (по возможности аналогичными временным таблицам):
-
Срок жизни — сессия Временное представление существует только в течение текущей сессии. Оно автоматически удаляется при завершении сессии.
-
Нет базы данных Вы не можете указывать имя базы данных для временного представления. Оно существует вне баз данных (в пространстве имен сессии).
-
Не реплицируются / без 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 не поддерживается для временных представлений (по аналогии с временными таблицами). Если вам нужно «заменить» временное представление, удалите его и создайте заново.
Примеры
Создайте временную исходную таблицу и временное представление поверх неё:
Выведите его DDL:
Удалите его:
Запрещено / ограничения
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), их данные могут передаваться на удалённые серверы во время выполнения распределённого запроса тем же способом, что и для временных таблиц.