Com les càrregues d'un Data warehouse es realitzen de manera periòdica, i a més és habitual la creació de taules agregades per millorar l'eficiència i temps de resposta dels nostres informes, un recurs d'optimització física que pot aportar grans millores és la utilització de vistes materialitzades.
La vista materialitzada no és més que una vista, definida amb una sentència SQL, de la qual a més d'emmagatzemar la seva definició, s'emmagatzemen les dades que retorna, realitzant una càrrega inicial i després cada cert temps un refresc dels mateixos.
Així, si tenim un Datawarehouse que s'actualitza diàriament, podríem utilitzar vistes materialitzades per anar actualitzant taules intermèdies que alimentin els nostres esquemes de DWH, o directament per implementar taules agregades que es refrescaran a partir de les nostres taules basi.
La creació d'aquest tipus de vistes no tan complexa com pot semblar, el més important és tenir clar cada quant temps volem actualitzar la informació de les vistes, i quin mètode de refresc utilitzar.
CREATE MATERIALIZED VIEW la meva_vista_materialitzada
[TABLESPACE el meu_tablespace]
[BUILD {IMMEDIATE | DEFERRED}]
[REFRESH {ON COMMIT | ON DEMAND | [START WITH data_inici] NEXT data_interval } |
{COMPLETI | FAST | FORCE} ]
[{ENABLE|DISABLE} QUERY REWRITE]
AS SELECT t1.camp1, t2.camp2
FROM la meva_taula1 t1 , la meva_taula2 t2
WHERE t1.camp_fk = t2.camp_pk
AND …
BUILD IMMEDIATE:
Les dades de la vista es carreguen en el mateix moment de la creació
BUILD DEFERRED:
Només es crea la definició, les dades es carregaran més avanci. Per realitzar aquesta càrrega es pot utilitzar la funció REFRESH del package DBMS_MVIEW:
begin
dbms_mview.refresh('la meva_vista_
end;
Cada quant temps es refrescaran:
REFRESH ON COMMIT:
Cada cop que es faci un commit en els objectes origin definits en la select
REFRESH ON DEMAND:
Com amb l'opció DEFERRED del BUILD, s'utilitzaran els procedures REFRESH, REFRESH_ALL_MVIEWS o REFRESH_DEPENDENT del package DBMS_MVIEW
REFRESH [START WITH data_inici] NEXT data_interval:
START WITH indica la data del primer refresc (data_inici sol ser un SYSDATE)
NEXT indica cada quant temps s'actualitzarà (data_interval podria ser SYSDATE +1 per realitzar el refresc una vegada al dia)
REFRESH COMPLETE:
El refresc es farà de totes les dades de la vista materialitzada, la recrearà completament cada cop que es llanci el refresc
REFRESH FAST:
El refresc serà incremental, és l'opció més recomanable, el de fast ya dóna una idea del perquè.
Aquest tipus de refresc té bastants restriccions segons el tipus de vista que s'estigui creant.
Es poden consultar en General Restrictions on Fast Refresh de la documentació oficial d'Oracle
Una de les coses importants a tenir en compte és que per poder utilitzar aquest mètode gairebé sempre és necessari haver creat abans un LOG de la Vista materialitzada, indicant els camps clau en els quals es basarà el manteniment de la vista.
S'utilitza la instrucció CREATE MATERIALIZED VIEW LOG ON:
CCREATE MATERIALIZED VIEW LOG ON la meva_taula_origen
WITH PRIMARY KEY
INCLUDING NEW VALUES;
REFRESH FORCE:
Amb aquest mètode s'indica que si és possible s'utilitzi el metodo FAST, i si no el COMPLETI.
Per saber si una vista materialitzada pot utilitzar el mètode FAST, el package DBMS_MVIEW proporciona el procedure EXPLAIN_MVIEW
ENABLE QUERY REWRITE:
Es permet a la base de dades la reescritura de consultes
DISABLE QUERY REWRITE:
Es desactiva la reescritura de consultes
L'opció QUERY REWRITE és la que més anem a utilitzar si volem les vistes materialitzades per optimitzar nostre Data warehouse.
Aquesta opció permet crear taules agregades en forma de vistes materialitzades, i que quan es llanci una SELECT la base de dades pugui reescriure-la per consultar la taula o vista que vagi a retornar les dades sol·licitades en menys temps, tot de manera totalment transparent a l'usuari
L'únic que cal fer és crear les taules agregades com a vistes materialitzades amb QUERY REWRITE habilitat.
Són moltes combinacions, però la sentència final no és tan complexa.
Si volguéssim crear una vista materialitzada d'una taula que es refresqui un dia a la setmana, i de manera incremental faríem el següent:
CREATE MATERIALIZED VIEW LOG ON la meva_taula_origen
WITH PRIMARY KEY
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW la meva_vista_materialitzada
REFRESH FAST NEXT SYSDATE + 7
AS SELECT camp1, camp2, camp8
FROM la meva_taula_origen
WHERE camp2 > 5000;
Aquesta vista podria servir-nos per alimentar la càrrega d'un Data Mart que es realitzés setmanalment. Podríem programar-la perquè es refresqués just abans de l'inici del procés de càrrega, o com a primer pas en l'ETL, i ja tindríem les dades necessàries actualitzades, i independents de l'origen de dades (no hauríem de molestar més a l'operacional). Un altre avantatge a tenir en compte és que si hi ha algun problema amb l'accés a les dades origen, si no els hem eliminat, en la vista materialitzada encara tindrem les dades de l'últim refresc, amb el que encara que el refresc fallés no ens trobaríem un error que trunqués la càrrega de nostre Data Warehouse, o una taula buida.
Per descomptat, en les condicions del WHERE podríem seleccionar només els registres necessaris, només els de l'últim mes, etc.
Un altre exemple important seria la utilització de vistes materialitzades per la creació de taules agregades:
CREATE MATERIALIZED VIEW vendes_agregades_mv
BUILD IMMEDIATE
REFRESH COMPLETI
ENABLE QUERY REWRITE
AS
SELECT aneu_producte, sum(import) total_vendes
FROM vendes;
Amb aquesta senzilla sentència es crearia una taula agregada de total de vendes per producte d'una suposada taula de vendes que seria la taula de fets.
A nivell de sessió també caldria assegurar-se que l'opció QUERY_REWRITE estigués activada. Per si per ventura s'habilita amb
ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE;
Si ara dintre d'aquesta sessió s'executa la sentència
SELECT sum(import)
FROM vendes;
la base de dades prepararà el pla d'execució tenint en compte la vista materialitzada creada i internament realitzarà la selecció sobre la vista vendes_agregades_mv.
Una manera senzilla de comprovar-ho, apart d'examinar el pla d'execució, o de comparar temps abans i després de la creació de la vista, o desactivant el QUERY_REWRITE, és comprovar que aquesta sentència retorna resultats en el mateix temps que la sentència
SELECT sum(import)
FROM vendes_agregades_mv;
Per consultar més detalls, o la sintaxi completa de la creació de vistes materialitzades en el capítol Create Materialized View del manual de referència SQL d'Oracle
Amb enterprise manager o amb la consola web de la base de dades també es poden crear les vistes materialitzades d'una manera més assistida, però igualment és important tenir clars els conceptes abans de fer-ho.
