Una Vista (View) es un objeto de Oracle que al consultarlo ejecuta por detrás una query y nos devuelve el resultado (donde la query puede acceder a una o varias tablas, otras vistas, utilizar funciones, etc). Cada vez que consultamos la vista el motor de base de datos ejecuta por detrás la query y va a buscar los datos al origen. Las vistas no ocupan espacio físico, ya que no almacenan datos. No hay diferencias en rendimiento si ejecutamos la query directamente o lo hacemos a través de una vista, ya que el motor debe calcular igualmente el plan de ejecución e ir a por los datos. En los proyectos en los que he participado normalmente usamos vistas cuando necesitamos recuperar los datos actualizados a través de queries complejas (joins entre varias tablas y/o vistas) o calcular KPIs. A diferencia de los procedimientos almacenados (stored procedures), que se ejecutan a demanda y persisten los datos en tablas, por lo que para procesos batch cumplen su función, pero no cuando necesitamos recuperar la foto actualizada del momento.
Por contra, una Vista Materializada (Materialized View) es otro tipo de objeto de Oracle que aunque técnicamente es lo mismo que una Vista (ejecuta una consulta sql por detrás), lo que hace es almacenar físicamente en caché el resultado de ejecutar esa query en un determinado momento, de forma que cada vez que consultemos la Vista Materializada lo que vamos a recuperar es lo que había en el origen en el momento en el que se creó o se refrescó la VM. El uso principal de este tipo de objetos es para agilizar procedimientos en los que hay queries muy largas y complejas. Esas queries se dividen en varias secciones y se generan vistas materializadas que se generan al principio del código y se utilizan como fuente más adelante. En mi experiencia, siempre hemos usado tablas temporales en lugar de vistas materializadas porque ofrecen más ventajas: permiten manipular la estructura de datos; no se persisten en la caché, si no en la propia base de datos.
A modo de resumen rápido:
Vista | Vista materializada |
---|---|
No se persisten datos, no ocupa espacio físico | Se persisten los datos en la BD, por lo que ocupa espacio físico |
Mismo rendimiento que ejecutar query directamente | Mejor rendimiento, los datos ya están cacheados |
Cada vez que se ejecuta se obtiene una foto actualizada | La foto de los datos es de cuando se generó o actualizó por última vez |
La sintaxis para crear una Vista materializada es:
CREATE MATERIALIZED VIEW nueva_vista_materializada
[TABLESPACE nuestro_tablespace]
[BUILD {IMMEDIATE | DEFERRED}]
[REFRESH {ON COMMIT | ON DEMAND | [START WITH fecha_inicial] NEXT intervalo_tiempo } |
{COMPLETE | FAST | FORCE | NEVER} ]
[{ENABLE|DISABLE} QUERY REWRITE]
AS SELECT tabla1.campo_a, tabla2.campo_b
FROM tabla1 , tabla2
WHERE tabla1.campo_a = tabla2.campo_a
Donde podemos especificar de qué forma queremos que se recuperen los datos: de forma inmediata o en otro momento:
- BUILD IMMEDIATE: El resultado se almacena al ejecutar la query
- BUILD DEFERRED: Sólo se crea la definición, el resultado se almacenará más adelante. Para ello podemos utilizar cuando queramos llenarla la función
REFRESH
del paquete de OracleDBMS_MVIEW
.
También podemos especificar cada cuánto tiempo o cuándo queremos que se actualicen los datos de la vista:
- REFRESH ON COMMIT: los datos se actualizan cada vez que se haga
COMMIT
sobre los objetos fuente. - REFRESH ON DEMAND: sólo se actualizarán cuando se haga manualmente a través de las funciones
REFRESH
de Oracle (más adelante se explica cuáles son y cómo invocarlas). - REFRESH [START WITH fecha_inicial] NEXT intervalo_tiempo: con esta sentencia podemos establecer una actualización periódica de la vista. La fecha_inicial puede definirse como sysdate y el intervalo_tiempo cada cuanto tiempo queremos realizar la tarea (podemos incrementar numéricamente el sysdate)
Y especificar si permitimos a Oracle o no reescribir las queries cuando en una consulta se intente acceder a las tablas origen, de forma que por detrás el duende de Oracle ataque directamente a las vistas materializadas, cuyo acceso y recuperación de datos es más rápido, sin que el usuario necesite hacer nada. Esto sólo lo hará el Optimizador de Oracle si la consulta lo permite (que las tablas a las que va a buscar la información coinciden con las tablas origen de la vista materializada).
- ENABLE QUERY REWRITE: Oracle puede reescribir las queries
- DISABLE QUERY REWRITE: lo contrario
La ventaja de este tipo de objeto la encontramos cuando la query asociada es muy compleja, tiene numerosos joins y se utiliza con frecuencia, ya que nos permite mejorar el rendimiento de la SQL al tenerla almacenada en memoria y ejecutarse una sóla vez. Sin embargo, el principal hándicap es que nos vemos obligados a mantenerla actualizada de forma regular para no perder calidad en los datos. Para ello podemos definir en el script de creación de la Vista Materializada el tipo de actualización que tendrá al ejecutar los métodos propios de Oracle para refrescarla. Existen los siguientes tipos de actualización para una Vista materializada
- FAST: Es la opción más recomendada por su rendimiento. Es una actualización incremental, es decir, sólo actualiza los registros que hayan cambiado. Para que esta opción funcione correctamente necesitamos generar estadísticas de la vista para que Oracle esté al tanto de los cambios. La forma de hacerlo es creando un log de la vista materializada sobre la PK de cada tabla origen.
CREATE MATERIALIZED VIEW LOG ON tabla_origen
WITH PRIMARY KEY
INCLUDING NEW VALUES;
- COMPLETE: regenera por completo el resultado al borrar y volver a ejecutar de nuevo la query.
- FORCE: Es el valor por defecto. En caso de que se pueda, se ejecutará el
FAST
; si no, elCOMPLETE
. - NEVER: nunca se refresca la vista.
Si modificamos el origen y queremos que éste se refleje en la Vista materializada, tenemos que invocar a una función del paquete DBMS_MVIEW
de Oracle que se encarga de actualizar los datos. Tenemos dos a nuestra disposición:
- DBMS_MVIEW.REFRESH: con este método pasamos por parámetro la Vista Materializada para que se actualice:
begin
DBMS_MVIEW.REFRESH('TABLA_EMPLEADOS');
end;
- DBMS_MVIEW.REFRESH_DEPENDENT: mientras que con este lo que le pasamos por parámetro son todas las tablas origen de las que depende la vista:
begin
DBMS_MVIEW.REFRESH_DEPENDENT('TABLA_ORIGEN_1', 'TABLA_ORIGEN_2', 'TABLA_ORIGEN_3');
end;
Excelente explicación en todos los sentidos.
Muy bien explicado el concepto, las ventajas.
Muchas gracias Ángel.
Un saludo
Gracias Por Tomarse el Tiempo de Explicar y Hacerlo Bien…
@Jelly muchas gracias por pasarte por aquí a comentarlo.
Una pregunta, Si «los objetos fuente» no estan disponibles en cierto momento la vista materializada sigue funcionando?,gracias, saludos
Hola Luis,
Sí, la vista materializada hace una foto de las tablas de origen, pero no las necesita para recuperar de nuevo esta información. En cambio la VISTA sí que necesita que el origen siga existiendo.
Un saludo
Hola Marcos.
entonces las vistas normales no ocupan espacio? no como las materializadas que esas si que conlleva espacio y datos. es asi?
un saludo y gracias por tus aportes
Hola Sergio,
Efectivamente, una vista no ocupa espacio físico, es una consulta almacenada que cuando se ejecute, ataca sobre el origen. Una vista materializada SÍ almacena los datos.
Un saludo!!
De los pocos blogs en los cuales se explica muy bien!! Felicidades!
muy bien explicado , muchas gracias
muchas gracias por vuestros comentarios
hola, muy buen blog.
Vamos a ver si me hago entender jeje.
Yo quiero crear una VM sobre un objeto que es un sinónimo creado con dblink a otra base de datos (por ejemplo informix).
Se puede hacer?
muchas gracias
Puedes crear una vista materializada de otro objeto, no deja de ser «almacenar» el resultado de una query.