Vista normal
Vista parametrizada
system.columns.
Además, las consultas DESCRIBE solo funcionarían si se proporcionan parámetros.
Vista materializada
OR REPLACE e IF NOT EXISTS son mutuamente excluyentes: combinarlos da lugar a un error de sintaxis.
CREATE OR REPLACE MATERIALIZED VIEW
CREATE OR REPLACE MATERIALIZED VIEW reemplaza de forma atómica una vista materializada existente y su tabla de almacenamiento subyacente (si la hay). La operación requiere un motor de base de datos Atomic o Replicated.
- Sin la cláusula
TO: se elimina la tabla interna anterior y se crea una nueva. Los datos existentes en la tabla interna se pierden, salvo que se especifiquePOPULATE. - Con la cláusula
TO: solo se reemplaza la definición de la vista; la tabla de destino y sus datos no se ven afectados. - Compatible con
REFRESH,ON CLUSTERy todas las opciones del motor.POPULATEsolo se admite en bases de datosAtomic; se rechaza en bases de datosReplicated(consulte la nota sobrePOPULATEmás abajo). - Requiere los privilegios
CREATE VIEWyDROP VIEW.
CREATE OR REPLACE MATERIALIZED VIEW solo es compatible con los motores de base de datos Atomic o Replicated. No es compatible con el motor de base de datos Ordinary.TO [db].[table], debes especificar ENGINE: el motor de tabla para almacenar los datos.
Al crear una vista materializada con TO [db].[table], también puedes usar POPULATE para rellenar la tabla de destino con datos históricos de los datos de origen existentes (la tabla de destino ya puede contener datos, en cuyo caso se añaden las filas rellenadas). POPULATE no se puede combinar con REFRESH: una vista materializada actualizable se rellena mediante su primera actualización, por lo que POPULATE cargaría los datos iniciales dos veces (usa EMPTY para omitir la primera actualización en su lugar).
Una vista materializada se implementa de la siguiente manera: al insertar datos en la tabla especificada en SELECT, una parte de los datos insertados se transforma mediante esta consulta SELECT, y el resultado se inserta en la vista.
Las vistas materializadas en ClickHouse usan nombres de columna en lugar del orden de las columnas durante la inserción en la tabla de destino. Si algunos nombres de columna no están presentes en el resultado de la consulta
SELECT, ClickHouse usa un valor predeterminado, incluso si la columna no es Nullable. Una práctica segura es agregar alias para cada columna al usar vistas materializadas.Las vistas materializadas en ClickHouse se implementan más bien como desencadenadores de inserción. Si hay alguna agregación en la consulta de la vista, se aplica solo al lote de datos recién insertados. Cualquier cambio en los datos existentes de la tabla de origen (como UPDATE, DELETE, DROP PARTITION, etc.) no modifica la vista materializada.Las vistas materializadas en ClickHouse no tienen un comportamiento determinista en caso de errores. Esto significa que los bloques que ya se hayan escrito se conservarán en la tabla de destino, pero todos los bloques posteriores al error no.De forma predeterminada, si el envío a una de las vistas genera una excepción, la consulta INSERT falla. No se garantiza que, para ese momento, el bloque ya haya llegado a la tabla de origen: eso depende del momento en la canalización de inserción, no del error de la vista. Reintente el INSERT fallido con deduplicación de inserción (insert_deduplicate, deduplicate_blocks_in_dependent_materialized_views) para obtener entrega exactly-once a la tabla de origen y a todas las vistas dependientes.Establecer materialized_views_ignore_errors=true en la consulta INSERT solo cambia el informe de errores: cada error de vista se registra como una advertencia y la consulta INSERT se completa correctamente. La entrega al destino de la vista que falla es parcial: los bloques procesados antes de la excepción se conservan, y el bloque que falla más cualquier bloque posterior se descartan de esa vista. Las vistas aguas abajo de ese destino ven solo los bloques que sí llegaron, por lo que su entrega también es parcial. Las vistas hermanas (y sus cadenas aguas abajo) que no generaron una excepción se escriben por completo, y en la tabla de origen se escribe como de costumbre. Como el INSERT informa éxito, el cliente no recibe ninguna señal de fallo y no se activa ningún reintento automático; use esta configuración solo cuando las escrituras en la tabla de origen no deban bloquearse por problemas del lado de la vista (por ejemplo, tablas system.*_log).materialized_views_ignore_errors es true de forma predeterminada para las tablas system.*_log.POPULATE, los datos existentes de la tabla de origen se insertan en la vista al crearla. De lo contrario, la vista contiene solo los datos insertados en la tabla de origen después de crearla.
Para un CREATE MATERIALIZED VIEW simple, POPULATE es atómico de forma predeterminada (configuración materialized_views_populate_atomically = 1): la vista se suscribe a las nuevas inserciones en la tabla de origen y se toma simultáneamente una instantánea de los datos existentes, bajo un breve bloqueo exclusivo en la tabla de origen, de modo que cada fila insertada de forma concurrente durante la carga inicial se entrega a la vista exactamente una vez: no se omite ni se duplica. A continuación, la carga inicial (que puede ser prolongada) lee la instantánea fijada sin mantener ningún bloqueo.
Esta es una atomicidad local de la ruta de inserción: el bloqueo exclusivo solo se serializa con las inserciones que adquieren el bloqueo de almacenamiento de esta tabla de origen en el mismo servidor, por lo que la garantía de entrega exactamente una vez cubre las inserciones que llegan a través de este servidor. No es una garantía para todo el clúster: las filas insertadas en otra réplica de un origen ReplicatedMergeTree, o mediante una ruta de escritura distribuida (por ejemplo, en una tabla Distributed o mediante ON CLUSTER), de forma concurrente con la carga inicial, quedan fuera de este alcance y aún pueden omitirse o duplicarse.
Si la carga inicial falla —por ejemplo, si no se puede adquirir el bloqueo exclusivo en una tabla de origen ocupada dentro de lock_acquire_timeout, o si el SELECT de la vista genera una excepción durante su ejecución—, la vista recién creada se elimina y la consulta CREATE falla, sin dejar nada de lo que creó, por lo que puede reintentarse sin más. Para la forma TO [db].[table], esta reversión elimina solo la vista, nunca la tabla de destino preexistente; pero las filas que la carga inicial fallida ya insertó en el destino permanecen allí, exactamente como después de un INSERT ... SELECT fallido en esa tabla, por lo que reintentar el CREATE las inserta de nuevo. Si el relleno debe ser exacto, vuelva a intentarlo con una tabla de destino truncada o nueva, o use un motor de deduplicación como ReplacingMergeTree.
La atomicidad requiere que la tabla de origen permita leer una instantánea fijada en un momento dado: la familia
MergeTree y Memory. Para cualquier otra fuente (una vista, Distributed, Merge, Buffer, la familia Log o una tabla que no esté en una base de datos Atomic), la carga inicial recurre al comportamiento heredado no atómico (registrado en el registro del servidor): los datos existentes se leen con una instantánea independiente y no coordinada, por lo que las filas insertadas durante la carga inicial pueden omitirse o duplicarse. En ese caso, cree la vista y ejecute un INSERT ... SELECT por separado si necesita datos exactos. Establecer materialized_views_populate_atomically = 0 fuerza este comportamiento heredado para todas las fuentes.La carga inicial atómica se aplica únicamente a CREATE MATERIALIZED VIEW simple. CREATE OR REPLACE / REPLACE MATERIALIZED VIEW ... POPULATE siempre usan la carga inicial heredada no atómica.POPULATE no es compatible con las bases de datos Replicated (use database_replicated_allow_heavy_create para anularlo) ni con ClickHouse Cloud. Cuando se habilita mediante esa sobrescritura, la carga inicial siempre es la heredada no atómica: una carga inicial fallida no podría revertirse de forma coherente en todas las réplicas.SELECT puede contener DISTINCT, GROUP BY, ORDER BY, LIMIT. Tenga en cuenta que las transformaciones correspondientes se realizan de forma independiente en cada bloque de datos insertados. Por ejemplo, si se establece GROUP BY, los datos se agregan durante la inserción, pero solo dentro de un único paquete de datos insertados. Los datos no se volverán a agregar después. La excepción es cuando se usa un ENGINE que realiza la agregación de datos por sí mismo, como SummingMergeTree.
Si la vista materializada usa la construcción TO [db.]name, puede aplicar DETACH a la vista, ejecutar ALTER en la tabla de destino y luego hacer ATTACH de la vista previamente separada con DETACH.
Las vistas tienen el mismo aspecto que las tablas normales. Por ejemplo, aparecen en el resultado de la consulta SHOW TABLES.
Para eliminar una vista, use DROP VIEW. Aunque DROP TABLE también funciona para las VIEW.
SQL security
DEFINER y SQL SECURITY permiten especificar qué usuario de ClickHouse se utilizará al ejecutar la consulta subyacente de la vista.
SQL SECURITY tiene tres valores válidos: DEFINER, INVOKER o NONE. Puede especificar cualquier usuario existente o CURRENT_USER en la cláusula DEFINER.
La siguiente tabla explica qué permisos se requieren para cada usuario al seleccionar datos de una vista.
Tenga en cuenta que, independientemente de la opción de SQL security, en todos los casos sigue siendo necesario tener GRANT SELECT ON <view> para poder leer de ella.
SQL SECURITY NONE es una opción obsoleta. Cualquier usuario con permisos para crear vistas con SQL SECURITY NONE podrá ejecutar cualquier consulta arbitraria.
Por lo tanto, es necesario tener GRANT ALLOW SQL SECURITY NONE TO <user> para crear una vista con esta opción.DEFINER/SQL SECURITY, el resultado depende de la configuración del servidor ignore_empty_sql_security_in_create_view_query.
Con su valor predeterminado de true, la consulta se almacena tal como se escribió y la vista obtiene un tipo de SQL security vacío. Una vista normal se ejecuta entonces con los permisos del invocador y, en el caso de una vista materializada con una tabla de destino especificada explícitamente, se omiten las comprobaciones de acceso a esa tabla de destino: insertar en la tabla fuente no requiere el privilegio INSERT en la tabla de destino, y leer de la vista no requiere el privilegio SELECT sobre ella.
Con false, los siguientes valores predeterminados se escriben en la definición de la vista en el momento de crearla:
SQL SECURITY:INVOKERpara las vistas normales (configurable mediantedefault_normal_view_sql_security) yDEFINERpara las vistas materializadas (configurable mediantedefault_materialized_view_sql_security)DEFINER:CURRENT_USER(configurable mediantedefault_view_definer)
DEFINER/SQL SECURITY conserva el tipo de SQL security vacío.
Para cambiar SQL security de una vista existente, use
Ejemplos
Live View
Vista materializada actualizable
interval es una secuencia de intervalos simples:
REFRESH debe especificar al menos uno de EVERY, AFTER o DEPENDS ON. REFRESH sin más (sin ninguno de ellos) se rechaza. REFRESH DEPENDS ON ... sin EVERY/AFTER es una forma abreviada de REFRESH AFTER 0 SECOND DEPENDS ON ...; consulta Dependencias de actualización más abajo.
Ejecuta periódicamente la consulta correspondiente y almacena su resultado en una tabla.
- Si se especifica
APPEND, cada actualización inserta filas en la tabla sin eliminar las existentes. La inserción no es atómica, igual que en una consultaINSERT INTO ... SELECTnormal. - De lo contrario, cada actualización reemplaza atómicamente el contenido previo de la tabla.
- No hay trigger de inserción. Cuando se insertan datos nuevos en la tabla especificada en
SELECT, no se envían automáticamente a la vista materializada actualizable. En su lugar, los datos solo se insertan durante las ejecuciones de actualización periódicas o manuales. - La consulta
SELECTno tiene restricciones. Se permiten funciones de tabla (por ejemplo,url()), vistas, UNION y JOIN.
La configuración de la parte
REFRESH ... SETTINGS de la consulta corresponde a los parámetros de actualización (por ejemplo, refresh_retries), y es distinta de la configuración normal (por ejemplo, max_threads). La configuración normal puede especificarse con SETTINGS al final de la consulta.Programación de actualización
RANDOMIZE FOR ajusta aleatoriamente el momento en que se realiza cada actualización, por ejemplo:
REFRESH EVERY 1 MINUTE tarda 2 minutos en actualizarse, simplemente se actualizará cada 2 minutos. Si después se vuelve más rápida y empieza a actualizarse en 10 segundos, volverá a actualizarse cada minuto. (En particular, no se actualizará cada 10 segundos para compensar actualizaciones omitidas: no existe tal retraso acumulado).
Normalmente, la primera actualización se inicia inmediatamente después de crear la vista materializada: el tiempo transcurrido desde la última actualización es infinito, por lo que cualquier programación indica que es momento de actualizarla. Si se especifica EMPTY, esta actualización inicial se omite y la primera actualización se realiza en el siguiente momento programado; por ejemplo, para EVERY 1 HOUR, la primera actualización se realizará al final de la hora actual.
En una DB Replicated
APPEND, la coordinación puede deshabilitarse con SETTINGS all_replicas = 1. Esto hace que las réplicas realicen las actualizaciones de forma independiente. En este caso, ReplicatedMergeTree no es necesario.
En el modo no APPEND, solo se admite la actualización coordinada. Para una actualización no coordinada, use la base de datos Atomic y la consulta CREATE ... ON CLUSTER para crear vistas materializadas actualizables en todas las réplicas.
La coordinación se realiza mediante Keeper. La ruta del znode se determina mediante la configuración de servidor default_replica_path.
Dependencias de actualización
DEPENDS ON sincroniza las actualizaciones de diferentes tablas:
DEPENDS ON solo funciona entre vistas materializadas actualizables. En particular, si la vista de la que depende usa TO <table>, asegúrate de usar el nombre de la vista y no el de la tabla. Si la lista de DEPENDS ON contiene una tabla normal, una vista no actualizable o un error tipográfico, la vista no se actualizará nunca y mostrará el estado MissingDependencies en system.view_refreshes. Las dependencias pueden modificarse o eliminarse con ALTER; consulta Cambiar los parámetros de actualización.Uso de DEPENDS ON para una latencia de propagación constante
REFRESH EVERY con el mismo período, la dependencia se aplica en cada franja horaria.
P. ej., supongamos que las vistas X e Y usan REFRESH EVERY 1 HOUR, y que Y lee de la tabla de salida de X. Sin dependencias, Y normalmente vería los datos de X de la actualización de la hora anterior. Con DEPENDS ON X, la actualización de Y de las 11:00 solo comenzará después de que finalice la actualización de X de las 11:00.
Uso de DEPENDS ON para el procesamiento de flujo por lotes
REFRESH EVERY, la vista dependiente X se actualiza si todas sus dependencias se han actualizado al menos una vez desde la última actualización de X. REFRESH AFTER T añade un retraso: la vista dependiente iniciará la actualización T unidades de tiempo después de que la dependencia complete una actualización.
Se permiten las dependencias circulares y son útiles. Considere este grafo de vistas materializadas actualizables:
- X toma un lote de filas de un flujo y las coloca en una tabla.
- Luego, Y y Z leen de esa tabla, realizan agregaciones distintas y añaden los resultados a otras tablas.
- Una vez que el lote se ha procesado por completo, X toma el siguiente lote y el ciclo se repite.
SYSTEM REFRESH VIEW manual después de cada reinicio, en lugar de solo una vez tras crear las vistas.
Parámetros de actualización
refresh_retries- Cuántas veces reintentar si la consulta de actualización falla con una excepción. Si fallan todos los reintentos, se pasa a la siguiente hora de actualización programada. 0 significa que no hay reintentos; -1, que los reintentos son infinitos. Predeterminado: 2.refresh_retry_initial_backoff_ms- Retraso antes del primer reintento, sirefresh_retriesno es cero. Cada reintento posterior duplica el retraso, hastarefresh_retry_max_backoff_ms. Predeterminado: 100 ms.refresh_retry_max_backoff_ms- Límite del crecimiento exponencial del retraso entre intentos de actualización. Predeterminado: 60000 ms (1 minuto).all_replicas- En una base de datos Replicated conAPPEND, controla si todas las réplicas se actualizan de forma independiente o si solo una réplica se actualiza en cada momento programado. No se puede cambiar después de crear la vista. Predeterminado:false.
Cambiar los parámetros de actualización
ALTER TABLE ... MODIFY REFRESH:
EVERY o AFTER) es obligatoria: la sentencia siempre sustituye todos los parámetros de actualización —la programación, RANDOMIZE FOR, DEPENDS ON y los parámetros de actualización— por los especificados. Todo lo que se omita se restablece a su valor predeterminado (configuración) o se elimina (dependencias, aleatorización).
-
Para cambiar solo los parámetros de actualización (por ejemplo,
refresh_retries), repita la programación actual: -
ALTER TABLE ... MODIFY SETTING refresh_retries = ...no es compatible con las vistas materializadas; debe hacerse medianteMODIFY REFRESH. -
No se admite añadir ni quitar
APPEND. -
La configuración
all_replicasno puede cambiarse después de la creación.
Otras operaciones
system.view_refreshes. En particular, incluye el progreso de la actualización (si está en curso), la hora de la última y de la próxima actualización, y el mensaje de excepción si una actualización falló.
Para detener, iniciar, activar o cancelar actualizaciones manualmente, use SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW.
Para esperar a que se complete una actualización, use SYSTEM WAIT VIEW. En particular, resulta útil para esperar a que termine la actualización inicial tras crear una vista.
Dato curioso: la consulta de actualización puede leer de la vista que se está actualizando y ver la versión de los datos anterior a la actualización. Esto significa que puede implementar el juego de la vida de Conway: https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==
Window View
MATERIALIZED VIEW. Una window view necesita un motor de almacenamiento interno para guardar datos intermedios. El almacenamiento interno puede especificarse mediante la cláusula INNER ENGINE; la window view usará AggregatingMergeTree como motor interno predeterminado.
Al crear una window view sin TO [db].[table], debe especificar ENGINE, el motor de tabla para almacenar los datos.
Funciones de ventana de tiempo
ATRIBUTOS DE TIEMPO
time_attr de la función de ventana de tiempo en una columna de la tabla o mediante la función now(). La siguiente consulta crea una window view con tiempo de procesamiento.
WATERMARK.
Window view proporciona tres estrategias de watermark:
STRICTLY_ASCENDING: Emite un watermark con la marca temporal máxima observada hasta el momento. Las filas con una marca temporal inferior a la marca temporal máxima no se consideran tardías.ASCENDING: Emite un watermark con la marca temporal máxima observada hasta el momento menos 1. Las filas con una marca temporal igual o inferior a la marca temporal máxima no se consideran tardías.BOUNDED: WATERMARK=INTERVAL. Emite watermarks que corresponden a la marca temporal máxima observada menos el retraso especificado.
WATERMARK:
ALLOWED_LATENESS=INTERVAL. Un ejemplo de gestión de la tardanza es:
SELECT especificada en la window view mediante la sentencia ALTER TABLE ... MODIFY QUERY. La estructura de datos resultante de la nueva consulta SELECT debe ser la misma que la de la consulta SELECT original, con o sin la cláusula TO [db.]name. Tenga en cuenta que los datos de la ventana actual se perderán porque el estado intermedio no se puede reutilizar.
Supervisión de nuevas ventanas
TO para enviar los resultados a una tabla.
LIMIT para definir el número de actualizaciones que se recibirán antes de finalizar la consulta. La cláusula EVENTS puede usarse para obtener una forma abreviada de la consulta WATCH, donde, en lugar del resultado de la consulta, solo se obtiene la watermark más reciente de la consulta.
Configuración
window_view_clean_interval: El intervalo de limpieza de window view, en segundos, para liberar datos obsoletos. El sistema conservará las ventanas que no se hayan activado por completo según la hora del sistema o la configuración deWATERMARK, y eliminará el resto de los datos.window_view_heartbeat_interval: El intervalo de heartbeat, en segundos, para indicar que la consulta watch sigue activa.wait_for_window_view_fire_signal_timeout: Tiempo de espera para recibir la señal de activación de window view durante el procesamiento por tiempo de evento.
Ejemplo
data, cuya estructura es:
WATCH para obtener los resultados.
data,
WATCH debería mostrar los resultados de la siguiente manera:
TO.
*window_view*).
Uso de Window View
- Monitoreo: Agrega y calcula las métricas de los logs a lo largo del tiempo, y envía los resultados a una tabla de destino. El dashboard puede usar la tabla de destino como tabla de origen.
- Análisis: Agrega y preprocesa automáticamente los datos dentro de la ventana de tiempo. Esto puede ser útil al analizar una gran cantidad de logs. El preprocesamiento elimina cálculos repetidos en múltiples consultas y reduce la latencia de las consultas.
- Blog: Cómo trabajar con datos de series temporales en ClickHouse
- Blog: Creación de una solución de observabilidad con ClickHouse - Parte 2 - Trazas
Vistas temporales
- Duración de la sesión Una vista temporal existe solo durante la sesión actual. Se elimina automáticamente cuando la sesión finaliza.
- Sin base de datos No se puede calificar una vista temporal con un nombre de base de datos. Existe fuera de las bases de datos (en el espacio de nombres de la sesión).
-
No replicadas / sin ON CLUSTER
Los objetos temporales son locales a la sesión y no pueden crearse con
ON CLUSTER. - Resolución de nombres Si un objeto temporal (tabla o vista) tiene el mismo nombre que un objeto persistente y una consulta hace referencia a ese nombre sin una base de datos, se usa el objeto temporal.
-
Objeto lógico (sin almacenamiento)
Una vista temporal solo almacena su texto
SELECT(usa internamente el motorView). No conserva datos y no admiteINSERT. -
Cláusula ENGINE
No es necesario especificar
ENGINE; si se indica comoENGINE = View, se ignora o se trata como la misma vista lógica. -
Seguridad / privilegios
Para crear una vista temporal se requiere el privilegio
CREATE TEMPORARY VIEW, que se concede implícitamente medianteCREATE VIEW. -
SHOW CREATE
Use
SHOW CREATE TEMPORARY VIEW view_name;para mostrar el DDL de una vista temporal.
Sintaxis
OR REPLACE no se admite para las vistas temporales (para mantener la coherencia con las tablas temporales). Si necesita “reemplazar” una vista temporal, elimínela y vuelva a crearla.
Ejemplos
No permitidos / limitaciones
CREATE OR REPLACE TEMPORARY VIEW ...→ no permitido (usaDROP+CREATE).CREATE TEMPORARY MATERIALIZED VIEW .../WINDOW VIEW→ no permitido.CREATE TEMPORARY VIEW db.view AS ...→ no permitido (sin calificador de base de datos).CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...→ no permitido (los objetos temporales son locales a la sesión).POPULATE,REFRESH,TO [db.table], motores internos y todas las cláusulas específicas de las MV → no aplicables a las vistas temporales.
Notas sobre las consultas distribuidas
Memory), sus datos pueden enviarse a servidores remotos durante la ejecución de consultas distribuidas, del mismo modo que ocurre con las tablas temporales.