Vistas Materializadas
Vistas materializadas
En este tutorial vamos a ver lo que son las vistas materializadas (materialized views) y vamos a hacer un ejemplo de creación de una vista materializada y su posterior uso. Lo primero de todo es recordar lo que es una vista en un modelo de base de datos relacional.
Una vista es una consulta almacenada que representa un conjunto de tablas (posiblemente de diferentes esquemas) a la que le vamos a poner un nombre y vamos a tratarla como si fuese una tabla más de nuestro esquema, pero sin llegar a ser realmente una tabla. Algo que tiene que quedar claro es que una vista NO guarda datos, sino que solo almacena la consulta que nos va a ayudar a acceder a los datos. Pero, ¿porqué usar vistas? es muy sencillo, principalmente hay dos motivos. El primer motivo es de seguridad, a lo mejor no necesitamos que determinados usuarios acceden a toda la información de la base de datos y simplemente queremos formar un conjunto de datos específicos para dichos usuarios. El segundo motivo tiene que ver con la estructura de nuestro modelo de datos, ya que si es bastante complejo o con muchas tablas nos puede ser muy útil crear este tipo de vistas para organizar una cierta información de modo que nos sea mucho más cómodo acceder a ella mediante consultas mucho más sencillas.
Definición
A diferencia de las vistas "normales" una vista materializada almacena físicamente los datos resultantes de ejecutar la consulta definida en la vista. Este tipo de vistas materializadas realizan una carga inicial de los datos cuando se definen y posteriormente con una frecuencia establecida se actualizan los datos de la misma.Con la utilización de vistas materializadas logramos aumentar el rendimiento de las consultas SQL además de ser un método de optimización a nivel físico en modelos de datos muy complejos y/o con muchos datos.
Una vez definida una vista materializada uno de los problemas que nos encontramos es el de la actualización de los datos. Como se ha comentado antes, estas vistas contienen fisicamente los datos de las "tablas base", por lo que si cambian los datos de estas tablas no se reflejarán en la vista materializada. Para ello necesitamos establecer un mecanismo de resfresco automático en el que tendremos que definir el tipo y la forma de refresco.
La sentencia SQL que nos permite definir una vista materializada es esta:
view plainprint?
1. CREATE MATERIALIZED VIEW nombre_vista
2. [TABLESPACE nombre_ts]
3. [PARALELL (DEGREE n)]
4. [BUILD {INMEDIATE|DEFERRED}]
5. [REFRESH {FAST|COMPLETE|FORCE|NEVER}|{ON COMMIT|ON DEMAND|[START WITH fecha_inicio] NEXT intervalo}]
6. [{ENABLE|DISABLE} QUERY REWRITE]
7. AS SELECT ... FROM ... WHERE ...
CREATE MATERIALIZED VIEW nombre_vista [TABLESPACE nombre_ts] [PARALELL (DEGREE n)] [BUILD {INMEDIATE|DEFERRED}] [REFRESH {FAST|COMPLETE|FORCE|NEVER}|{ON COMMIT|ON DEMAND|[START WITH fecha_inicio] NEXT intervalo}] [{ENABLE|DISABLE} QUERY REWRITE] AS SELECT ... FROM ... WHERE ...
Con la palabra BUILD establecemos la forma de carga de datos en la vista. Con la opción INMEDIATE (opción por defecto) se cargarán los datos justo después de crear la vista, mientras que con la opción DEFERRED se definirá la vista cuando se ejecute la sentencia SQL sin cargar ningún dato, que se cargarán cuando se realize el primer refresco de la vista.
Con la palabra REFRESH definimos el método y la frecuencia de refresco de los datos.
La palabra QUERY REWRITE establece si queremos que el optimizador de nuestra base de datos pueda reescribir las consultas. El optimizador, sabiendo que ya existe una determinada vista materializada, puede modificar internamente nuestra consulta sobre una determinada tabla, de tal forma que se mejore el rendimiento de la consulta devolviendo los mismos datos que la consulta original.
Refresco
Como es entendible la política de refresco de cada vista repende altamente de nuestras necesidades y requerimientos sobre la frecuencia de actualización de los datos de las "tablas base".
Tipos de refresco
* COMPLETE : se borrarán todos los datos de la vista y se volverá a ejecutar la consulta definida en la vista por lo que se recargarán fisicamente los datos de las "tablas base".
* FAST : podemos decir que este tipo de refresco es una actualización incremental, es decir, solo se refrescarán aquellos datos que se hayan modificado desde el último refresco. Evidentemente este tipo de refresco es mucho más fast ;-) que el complete. Pero, ¿cómo sabe la base de datos que datos se han modificado desde el último refresco? lo sabe gracias a que previamente hemos tenido que crear unos determinados log de la vista (VIEW LOG) sobre cada una de las "tablas base" de la vista materializada.
view plainprint?
1. CREATE MATERIALIZED VIEW LOG ON tabla_base
2. WITH PRIMARY KEY
3. INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON tabla_base WITH PRIMARY KEY INCLUDING NEW VALUES;
Hay que decir que si usamos funciones sum, avg, max, min, etcétera, no vamos a poder usar este tipo de refresco.
*
FORCE : si se puede realizar el refresco tipo FAST se ejecuta, y sino se realiza el refresco COMPLETE. Es el valor por defecto del tipo de refresco.
* NEVER : nunca se realizará un refresco de la vista.
Formas de refresco
* Refresco manual : mediante el paquete de PL/SQL DBMS_MVIEW podemos forzar a realizar un refresco usando para ello la función REFRESH.
view plainprint?
1. DBMS_MVIEW.REFRESH ('nombre_vista');
2.
DBMS_MVIEW.REFRESH ('nombre_vista');
Con la función REFRESH_DEPENDENT se refrescarán todas las vistas materializadas que tengan algunas de sus "tablas base" en la lista de tablas pasada como parámetro de entrada.
view plainprint?
1. DBMS_MVIEW.REFRESH_DEPENDENT ('tabla1, tabla2, tabla3, ... , tablaN');
2.
DBMS_MVIEW.REFRESH_DEPENDENT ('tabla1, tabla2, tabla3, ... , tablaN');
Con la función REFRESH_ALL_MVIEWS se refrescarán todas las vistas materializadas de nuestra base de datos.
* Refresco automático : este refresco automático podemos hacerlo usando la palabra ON COMMIT, con la que se fuerza al refresco de la vista en el momento en el que se haga un commit sobre una de las "tablas base" de dicha vista. Otro tipo de refresco automático es el llamado refresco programado, en el cual podemos definir el momento exacto en el que queremos que se refresque nuestra vista. Para ello tenemos que definir la fecha del refresco en formate datetime y el intervalo de este.
Ejemplo práctico
Una vez visto todos los detalles teóricos vamos a hacer un pequeño ejemplo práctico para ver como definir vistas materializadas y analizar sus comportamientos.
Lo primero que vamos a hacer es crear una tabla (SQL) en nuestra base de datos (Oracle 9) y insertar algunos datos.
1. CREATE TABLE tabla
2. (campo1 int PRIMARY KEY,
3. campo2 int);
4.
5. insert into tabla values (1,2);
6. insert into tabla values (2,298);
7. insert into tabla values (3,223);
8. insert into tabla values (4,121);
9. insert into tabla values (5,34);
10. insert into tabla values (6,34);
11. insert into tabla values (7,78);
12. insert into tabla values (8,44);
13. insert into tabla values (9,34);
14. insert into tabla values (10,12);
CREATE TABLE tabla (campo1 int PRIMARY KEY, campo2 int); insert into tabla values (1,2); insert into tabla values (2,298); insert into tabla values (3,223); insert into tabla values (4,121); insert into tabla values (5,34); insert into tabla values (6,34); insert into tabla values (7,78); insert into tabla values (8,44); insert into tabla values (9,34); insert into tabla values (10,12);
A continuación creamos un VIEW LOG para la anterior tabla.
view plainprint?
1. CREATE MATERIALIZED VIEW LOG ON tabla
2. WITH PRIMARY KEY
3. INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON tabla WITH PRIMARY KEY INCLUDING NEW VALUES;
Despúes creamos nuestra vista materializada.
1. CREATE MATERIALIZED VIEW tabla_vm
2. BUILD IMMEDIATE
3. REFRESH FAST ON COMMIT
4. AS SELECT * FROM tabla;
CREATE MATERIALIZED VIEW tabla_vm BUILD IMMEDIATE REFRESH FAST ON COMMIT AS SELECT * FROM tabla;
Como se puede ver, la definición de la vista es absurda, ya que es la propia tabla, pero para nuestro ejemplo nos servirá ya que lo que se pretende es ver el comportamiento de la vista materializada creada.
En la anterior sentencia SQL creamos una vista materializada de nombre tabla_vm que se cargará inicialmente justo cuando se ejecute (BUILD IMMEDIATE), se refrescarán solo aquellas entradas que se hallan modificado en la tabla base (FAST) y lo harán cuando se ejecute la acción de commit (ON COMMIT).
Vamos a ver si realmente la teoría se corresponde con la práctica. Inicialmente tanto la tabla base como la vista materializada contienen estos valores:
Cuando ejecutamos una sentencia sobre la tabla base que actualize un determinado dato de ella (update tabla set campo2 = 123 where campo1 = 1) podemos ver que se ha actualizado en la tabla base pero no en la vista materializada ya que aun no se ha lanzado el refresco.
tabla base - tabla
vista materializada - tabla_vm
Para que la vista se refresque y se actualize solo con el dato modificado en la tabla base tenemos que hacer COMMIT.
Como se puede ver en la imagen de arriba ya tenemos los datos totalmente actualizados en nuestra vista materializada.
Este pequeño ejemplo no tiene valor para poder analizar la mejora en el rendimiento al usar este tipo de vistas pero nos ha servido (...o eso espero...) para que se vea como se puede crear una vista materializada y como es su funcionamiento.
Para borrar la vista materializada creada tenemos que ejecutar la siguiente sentencia SQL.
1. drop materialized view tabla_vm;
Comentarios
Te quería avisar que las imágenes no las puedo visualizar.
Y también te quería comentar que en mi trabajo usamos Vistas Materializdas, con lo cual me gustaría aportar lo siguiente para mejorar aún más este artículo:
Si tenemos una Vista Materializada en una instancia y la misma tiene tablas bases en otra instancia (o sea que se refresca a través de un dblink) no permite hacer refrescos ONCOMMIT.
Muchas gracias por el espacio.
Saludos.