CREATE VIEW
Создаёт новое представление. Представления могут быть обычными, материализованными, обновляемыми материализованными и оконными (обновляемое материализованное представление и оконное представление являются экспериментальными функциями).
Обычное представление
Синтаксис:
Обычные представления не хранят никаких данных. Они просто выполняют чтение из другой таблицы при каждом доступе. Иными словами, обычное представление — это не что иное, как сохранённый запрос. При чтении из представления этот сохранённый запрос используется как подзапрос в предложении FROM.
Например, предположим, что вы создали представление:
и написали запрос:
Этот запрос полностью эквивалентен использованию подзапроса:
Параметризованное представление
Параметризованные представления похожи на обычные представления, но могут быть созданы с параметрами, которые не разрешаются немедленно. Эти представления могут быть использованы с табличными функциями, которые указывают имя представления как имя функции и значения параметров как её аргументы.
Выше создаётся представление для таблицы, которое может быть использовано как табличная функция, подставив параметры, как показано ниже.
Материализованное представление
Здесь содержится пошаговое руководство по использованию материализованных представлений.
Материализованные представления хранят данные, преобразованные соответствующим запросом SELECT.
При создании материализованного представления без указания TO [db].[table]
, необходимо указать ENGINE
— движок таблицы для хранения данных.
При создании материализованного представления с использованием TO [db].[table]
, нельзя использовать POPULATE
.
Материализованное представление реализовано следующим образом: при вставке данных в таблицу, указанную в SELECT
, часть вставленных данных преобразуется этим запросом SELECT
, и результат вставляется в представление.
Материализованные представления в ClickHouse используют имена столбцов вместо порядка столбцов во время вставки в целевую таблицу. Если некоторые имена столбцов отсутствуют в результате запроса SELECT
, ClickHouse использует значение по умолчанию, даже если столбец не является Nullable. Безопасной практикой будет добавление алиасов для каждого столбца при использовании материализованных представлений.
Материализованные представления в ClickHouse реализованы больше как триггеры вставки. Если в запросе представления есть агрегация, она применяется только к партии свежевставленных данных. Любые изменения существующих данных исходной таблицы (например, обновление, удаление, удаление раздела и т.д.) не влияют на материализованное представление.
Материализованные представления в ClickHouse не обладают детерминированным поведением в случае ошибок. Это означает, что блоки, которые уже были записаны, будут сохранены в целевой таблице, но все блоки после ошибки не будут записаны.
По умолчанию, если вставка в одно из представлений не удалась, запрос INSERT также не удастся, и некоторые блоки могут не быть записаны в целевую таблицу. Это можно изменить, используя настройку materialized_views_ignore_errors
(её нужно установить для запроса INSERT
), если установить materialized_views_ignore_errors=true
, то любые ошибки при записи в представления будут игнорироваться и все блоки будут записаны в целевую таблицу.
Также обратите внимание, что materialized_views_ignore_errors
установлено на true
по умолчанию для таблиц system.*_log
.
Если вы указываете POPULATE
, существующие данные таблицы вставляются в представление при его создании, как будто выполняется CREATE TABLE ... AS SELECT ...
. В противном случае запрос содержит только данные, вставленные в таблицу после создания представления. Мы не рекомендуем использовать POPULATE
, так как данные, вставленные в таблицу во время создания представления, не будут вставлены в него.
Учитывая, что POPULATE
работает как CREATE TABLE ... AS SELECT ...
, он имеет ограничения:
- Не поддерживается с реплицируемой базой данных
- Не поддерживается в ClickHouse cloud
Вместо этого можно использовать отдельный INSERT ... SELECT
.
Запрос SELECT
может содержать DISTINCT
, GROUP BY
, ORDER BY
, LIMIT
. Обратите внимание, что соответствующие преобразования выполняются независимо для каждого блока вставленных данных. Например, если установлен GROUP BY
, данные агрегируются при вставке, но только в пределах одного пакета вставленных данных. Данные не будут дополнительно агрегироваться. Исключение составляет использование движка ENGINE
, который самостоятельно выполняет агрегацию данных, например SummingMergeTree
.
Выполнение запросов ALTER на материализованных представлениях имеет ограничения, например, нельзя обновить запрос SELECT
, что может быть неудобно. Если материализованное представление использует конструкцию TO [db.]name
, вы можете DETACH
представить, выполнить ALTER
для целевой таблицы и затем ATTACH
ранее отсоединенное (DETACH
) представление.
Обратите внимание, что на материализованное представление влияет настройка optimize_on_insert. Данные сливаются перед вставкой в представление.
Представления выглядят так же, как и обычные таблицы. Например, они перечислены в результате запроса SHOW TABLES
.
Чтобы удалить представление, используйте DROP VIEW. Однако DROP TABLE
работает и для представлений.
Безопасность SQL
DEFINER
и SQL SECURITY
позволяют указать, какого пользователя ClickHouse использовать при выполнении базового запроса представления.
SQL SECURITY
имеет три допустимых значения: DEFINER
, INVOKER
или NONE
. Вы можете указать любого существующего пользователя или CURRENT_USER
в предложении DEFINER
.
Следующая таблица объяснит, какие права требуются от какого пользователя для того, чтобы выбрать данные из представления.
Обратите внимание, что независимо от опции безопасности 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
(настраивается через параметры)
Если представление подключено без указания DEFINER
/SQL SECURITY
, значение по умолчанию — это SQL SECURITY NONE
для материализованного представления и SQL SECURITY INVOKER
для обычного представления.
Чтобы изменить безопасность SQL для существующего представления, используйте:
Примеры
Live-представление
Эта функция устарела и будет удалена в будущем.
Для вашего удобства старая документация находится здесь
Обновляемое материализованное представление
где interval
— это последовательность простых интервалов:
периодически выполняет соответствующий запрос и сохраняет его результат в таблице.
- Если в запросе указано
APPEND
, каждое обновление добавляет строки в таблицу без удаления существующих строк. Вставка не является атомарной, как и обычный INSERT SELECT. - В противном случае каждое обновление атомарно заменяет предыдущие данные в таблице.
Различия от обычных необновляемых материализованных представлений:
- Нет триггера вставки. Т.е. когда новые данные вставляются в таблицу, указанную в SELECT, они НЕ автоматически попадают в обновляемое материализованное представление. Периодическое обновление выполняет весь запрос.
- Нет ограничений на запрос SELECT. Табличные функции (например,
url()
), представления, UNION, JOIN разрешены.
Настройки в части запроса REFRESH ... SETTINGS
являются настройками обновления (например, refresh_retries
), отличными от обычных настроек (например, max_threads
). Обычные настройки можно указать, используя SETTINGS
в конце запроса.
Расписание обновления
Пример расписания обновления:
RANDOMIZE FOR
случайным образом корректирует время каждого обновления, напр.:
В одно и то же время для данного представления может выполняться не более одного обновления. Например, если представление с REFRESH EVERY 1 MINUTE
обновляется 2 минуты, оно будет обновляться каждые 2 минуты. Если потом оно станет быстрее и начнёт обновляться за 10 секунд, оно вернется к обновлению каждую минуту. (В частности, оно не будет обновляться каждые 10 секунд, чтобы догнать отставание по пропущенным обновлениям — такого отставания нет.)
Кроме того, обновление начинается сразу после создания материализованного представления, если в запросе CREATE
не указано EMPTY
. Если EMPTY
указано, первое обновление происходит по расписанию.
В реплицируемых базах данных
Если обновляемое материализованное представление находится в реплицируемой базе данных, реплики координируются друг с другом таким образом, чтобы только одна реплика выполняла обновление в каждое запланированное время. Требуется движок таблицы ReplicatedMergeTree, чтобы все реплики видели данные, полученные в результате обновления.
В режиме APPEND
координация может быть отключена, используя SETTINGS all_replicas = 1
. Это заставляет реплики выполнять обновления независимо друг от друга. В этом случае ReplicatedMergeTree не требуется.
В нет режиме APPEND
поддерживается только координированное обновление. Для некоординированного используется база данных Atomic
и запрос CREATE ... ON CLUSTER
для создания обновляемых материализованных представлений на всех репликах.
Координация осуществляется через Keeper. Путь znode определяется настройкой сервера default_replica_path.
Зависимости
DEPENDS ON
синхронизирует обновления разных таблиц. Например, предположим, что существует цепочка из двух обновляемых материализованных представлений:
Без DEPENDS ON
оба представления начнут обновление в полночь, и destination
, как правило, будет видеть вчерашние данные в source
. Если мы добавим зависимость:
тогда обновление destination
начнёт выполняться только после завершения обновления source
за этот день, так что destination
будет основано на свежих данных.
Или, тот же результат можно достичь с помощью:
где 1 HOUR
может быть любым интервалом, меньшим, чем период обновления source
. Зависимая таблица не будет обновляться чаще, чем любая из её зависимостей. Это действительный способ установить цепочку обновляемых представлений, не указывая реальный период обновления больше одного раза.
Ещё несколько примеров:
REFRESH EVERY 1 DAY OFFSET 10 MINUTE
(destination
) зависит отREFRESH EVERY 1 DAY
(source
)
Если обновлениеsource
занимает больше 10 минут,destination
будет ждать его.REFRESH EVERY 1 DAY OFFSET 1 HOUR
зависит отREFRESH EVERY 1 DAY OFFSET 23 HOUR
Похоже на вышеприведённое, хотя соответствующие обновления происходят в разные календарные дни. Обновлениеdestination
на день X+1 будет ждать завершения обновленияsource
за день X (если оно занимает более 2 часов).REFRESH EVERY 2 HOUR
зависит отREFRESH EVERY 1 HOUR
2-часовое обновление происходит после 1-часового обновления каждые два часа, например, после полуночи, затем после 2 часов ночи и т.д.REFRESH EVERY 1 MINUTE
зависит отREFRESH EVERY 2 HOUR
REFRESH AFTER 1 MINUTE
зависит отREFRESH EVERY 2 HOUR
REFRESH AFTER 1 MINUTE
зависит отREFRESH AFTER 2 HOUR
destination
обновляется один раз после каждого обновленияsource
, то есть каждые 2 часа. Фактически1 MINUTE
игнорируется.REFRESH AFTER 1 HOUR
зависит отREFRESH AFTER 1 HOUR
В настоящее время это не рекомендуется.
DEPENDS ON
работает только между обновляемыми материализованными представлениями. Указание обычной таблицы в списке DEPENDS ON
приведёт к тому, что представление никогда не будет обновляться (зависимости могут быть удалены с помощью ALTER
, см. ниже).
Настройки
Доступные настройки обновления:
refresh_retries
- сколько раз повторить попытку, если запрос обновления завершится с исключением. Если все попытки не удачны, пропустить до следующего запланированного времени обновления. 0 означает отсутствие повторов, -1 означает бесконечные повторы. По умолчанию: 0.refresh_retry_initial_backoff_ms
- задержка перед первой попыткой повтора, еслиrefresh_retries
не равен нулю. Каждая последующая попытка повтора удваивает задержку, вплоть доrefresh_retry_max_backoff_ms
. По умолчанию: 100 мс.refresh_retry_max_backoff_ms
- ограничение на экспоненциальный рост задержки между попытками обновления. По умолчанию: 60000 мс (1 минута).
Изменение параметров обновления
Чтобы изменить параметры обновления:
Это заменяет все параметры обновления одновременно: расписание, зависимости, настройки и добавление (APPEND). Например, если таблица имела DEPENDS ON
, выполнение MODIFY REFRESH
без указания DEPENDS ON
удалит зависимости.
Другие операции
Статус всех обновляемых материализованных представлений доступен в таблице system.view_refreshes
. В частности, она содержит прогресс обновления (если оно выполняется), время последнего и следующего обновления, сообщение об исключении, если обновление завершилось ошибкой.
Для ручной остановки, запуска, вызова или отмены обновлений используйте SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW
.
Чтобы дождаться завершения обновления, используйте SYSTEM WAIT 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
— движок таблицы для хранения данных.
Временные оконные функции
Временные оконные функции используются для получения нижней и верхней границы окна записей. Оконное представление должно использоваться с временной оконной функцией.
ВРЕМЕННЫЕ АТРИБУТЫ
Оконное представление поддерживает время обработки и время события.
Время обработки позволяет оконному представлению выдавать результаты на основе времени локальной машины и используется по умолчанию. Это самое простое понятие времени, но оно не обеспечивает детерминированности. Атрибут времени обработки может быть определён путём установки 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
. Обратите внимание, что данные в текущем окне будут утеряны, поскольку промежуточное состояние не может быть повторно использовано.
Мониторинг новых окон
Оконное представление поддерживает запрос WATCH для мониторинга изменений или использование синтаксиса TO
для вывода результатов в таблицу.
Запрос WATCH
действует аналогично LIVE VIEW
. Можно указать LIMIT
, чтобы задать количество обновлений, которые необходимо получить перед завершением запроса. Опция EVENTS
может быть использована для получения краткой формы запроса WATCH
, где вместо результата запроса вы получите просто последние данные водяного знака запроса.
Настройки
window_view_clean_interval
: Интервал очистки оконного представления в секундах для освобождения устаревших данных. Система сохранит окна, которые не были полностью сработаны в соответствии с системным временем или конфигурациейWATERMARK
, а остальные данные будут удалены.window_view_heartbeat_interval
: Интервал сердцебиения в секундах, чтобы указать, что запрос наблюдения (watch) активен.wait_for_window_view_fire_signal_timeout
: Таймаут ожидания сигнала срабатывания оконного представления при обработке времени события.
Пример
Предположим, нам нужно подсчитать количество кликов по логам в интервале 10 секунд в таблице логов data
, структура которой:
Сначала мы создадим оконное представление с оконным интервалом в 10 секунд:
Затем используем запрос WATCH
, чтобы получить результаты.
Когда логи вставляются в таблицу data
,
Запрос WATCH
должен вывести результаты следующим образом:
В качестве альтернативы мы можем связать вывод с другой таблицей, используя синтаксис TO
.
Дополнительные примеры можно найти среди тестов состояния ClickHouse (они названы *window_view*
).
Использование оконных представлений
Оконные представления полезны в следующих сценариях:
- Мониторинг: Агрегация и вычисление метрик журналов по времени и вывод результатов в целевую таблицу. Панель мониторинга может использовать целевую таблицу как источник данных.
- Анализ: Автоматическая агрегация и предварительная обработка данных во временном окне. Это может быть полезно при анализе большого количества журналов. Предварительная обработка устраняет повторные вычисления в нескольких запросах и уменьшает задержку запроса.