Consulta. La siguiente es una consulta que utiliza tres tablas:
(Todo de acá en más está anonimizado, puede deslizarse algún error involuntario)
SELECT id
,id_dependencia
,descripcion_corta NOMBRE
,to_char(fecha_fallecimiento, 'YYYY-MM-DD') FECHA_FALLECIMIENTO
--DOMICILIO
,d.direccion DOMICILIO
,d.localidad
--,(select nombre_provincia from t_3 where cod_provincia = d.id_provincia) PROVINCIA
,p.nombre_provincia PROVINCIA
FROM t_1
,t_2 d
,t_3 p
WHERE id = d.Id_persona
AND d.id_tipo_domicilio = 1
AND cod_provincia = d.id_provincia;
Esta consulta es la traducción de otra consulta, porque las VM no permiten subconsultas para construirlas (nótese que PROVINCIA
está definida dos veces, porque no se puede tener un SELECT
anidado).
El problema que surge de esto, es que la consulta final termina haciendo un full scan de la tabla t_2
, que tiene los domicilios.
Y, ¿por qué se da esto? Porque la tabla t_3
está unida a t_2
por cod_provincia = d.id_provincia
, pero sin embargo, y la tabla t_1
se une a la t_2
por id = d.Id_persona
, pero de t_2
solo se requiere un tipo de domicilio.
El explain plan dice esto:
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Inst |IN-OUT|
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9081K| 1688M| | 615K (1)| 02:03:03 | | |
|* 1 | HASH JOIN | | 9081K| 1688M| | 615K (1)| 02:03:03 | | |
| 2 | REMOTE | t_3 | 24 | 384 | | 23 (0)| 00:00:01 | PADRRO | R->S |
|* 3 | HASH JOIN | | 9081K| 1550M| 989M| 615K (1)| 02:03:02 | | |
| 4 | REMOTE | T_2 | 9020K| 886M| | 430K (1)| 01:26:07 | PADRRO | R->S |
| 5 | TABLE ACCESS FULL| T_1 | 14M| 1025M| | 76389 (2)| 00:15:17 | | |
-----------------------------------------------------------------------------------------------------------
El problema está en el paso 4. Hace un acceso full a la tabla t_2
, porque está ejecutando este query:
SELECT "ID_PERSONA",
"LOCALIDAD",
"ID_PROVINCIA",
"DIRECCION"
FROM t_2 "D"
WHERE "ID_TIPO_DOMICILIO" = 1
Y por supuesto no está usando id_persona
como índice de entrada, si no que prioriza la claúsula where
. (id_persona
es índice, tipo_domicilio
no lo es)
Pregunta. En un query normal, poniendo un with
antes de la consulta, o buscando la provincia con un subquery, el problema no ocurre, por lo tanto la pregunta es, ¿cómo se puede construir una vista materializada para este esquema de base de datos que permita joinear las 3 tablas, y no haga un full scan de la tabla t_2
?
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
SQL_ID 0
-------------------------------------
SELECT "ID_PERSONA","LOCALIDAD","ID_PROVINCIA","DIRECCION" FROM t_2 WHERE
"ID_TIPO_DOMICILIO"=1 AND :1="ID_PERSONA" AND :2="ID_PROVINCIA"
Plan hash value: 3060586354
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 5 (100)| |
|* 1 | MAT_VIEW ACCESS BY INDEX ROWID| t_2 | 1 | 53 | 5 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | PK_DO1 | 1 | | 4 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID_PROVINCIA"=:2)
2 - access("ID_PERSONA"=:1 AND "ID_TIPO_DOMICILIO"=1)
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 5
-------------------------------------
SELECT "ID_PERSONA",,"LOCALIDAD","ID_PROVINCIA","DIRECCION" FROM t_2 WHERE
"ID_TIPO_DOMICILIO"=1
Plan hash value: 2225703109
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 429K(100)| |
|* 1 | MAT_VIEW ACCESS FULL| t_2 | 9020K| 455M| 429K (1)| 01:18:45 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID_TIPO_DOMICILIO"=1)