EXPLAIN PLAN también determina el costo de ejecutar la
sentencia SQL. En el costo calculado, entran en juego diversas variables como
por ejemplo el número de bloques leídos, tiempo de lectura, lectura simple o
multibloque, ciclos de procesador, velocidad de CPU, etc. pero en definitiva es
lo que hace que Oracle determine un plan de ejecución específico sobre todos
los calculados.
En el software de instalación del motor de base de datos
podemos encontrar un script de ejemplo con la definición de la output table
(PLAN_TABLE). La tabla de salida que finalmente
utilicemos debe tener los mismos nombres de columna y tipos de datos que
esta tabla. Por lo general , el nombre común de este script es utlxplan.sql en versiones anteriores a 10.2 y catplan.sql a partir de esta versión. Lo podemos encontrar en @?/rdbms/admin/
La definición de la PLAN_TABLE (output table) en el script catplan.sql es la siguiente:
SQL> desc plan_table
Name Null? Type
----------------------------------------- -------- ----------------------------
STATEMENT_ID VARCHAR2(30)
PLAN_ID NUMBER
TIMESTAMP DATE
REMARKS VARCHAR2(4000)
OPERATION VARCHAR2(30)
OPTIONS VARCHAR2(255)
OBJECT_NODE VARCHAR2(128)
OBJECT_OWNER VARCHAR2(30)
OBJECT_NAME VARCHAR2(30)
OBJECT_ALIAS VARCHAR2(65)
OBJECT_INSTANCE NUMBER(38)
OBJECT_TYPE VARCHAR2(30)
OPTIMIZER VARCHAR2(255)
SEARCH_COLUMNS NUMBER
ID NUMBER(38)
PARENT_ID NUMBER(38)
DEPTH NUMBER(38)
POSITION NUMBER(38)
COST NUMBER(38)
CARDINALITY NUMBER(38)
BYTES NUMBER(38)
OTHER_TAG VARCHAR2(255)
PARTITION_START VARCHAR2(255)
PARTITION_STOP VARCHAR2(255)
PARTITION_ID NUMBER(38)
OTHER LONG
OTHER_XML CLOB
DISTRIBUTION VARCHAR2(30)
CPU_COST NUMBER(38)
IO_COST NUMBER(38)
TEMP_SPACE NUMBER(38)
ACCESS_PREDICATES VARCHAR2(4000)
FILTER_PREDICATES VARCHAR2(4000)
PROJECTION VARCHAR2(4000)
TIME NUMBER(38)
QBLOCK_NAME VARCHAR2(30)
La definición de la PLAN_TABLE (output table) en el script catplan.sql es la siguiente:
SQL> desc plan_table
Name Null? Type
----------------------------------------- -------- ----------------------------
STATEMENT_ID VARCHAR2(30)
PLAN_ID NUMBER
TIMESTAMP DATE
REMARKS VARCHAR2(4000)
OPERATION VARCHAR2(30)
OPTIONS VARCHAR2(255)
OBJECT_NODE VARCHAR2(128)
OBJECT_OWNER VARCHAR2(30)
OBJECT_NAME VARCHAR2(30)
OBJECT_ALIAS VARCHAR2(65)
OBJECT_INSTANCE NUMBER(38)
OBJECT_TYPE VARCHAR2(30)
OPTIMIZER VARCHAR2(255)
SEARCH_COLUMNS NUMBER
ID NUMBER(38)
PARENT_ID NUMBER(38)
DEPTH NUMBER(38)
POSITION NUMBER(38)
COST NUMBER(38)
CARDINALITY NUMBER(38)
BYTES NUMBER(38)
OTHER_TAG VARCHAR2(255)
PARTITION_START VARCHAR2(255)
PARTITION_STOP VARCHAR2(255)
PARTITION_ID NUMBER(38)
OTHER LONG
OTHER_XML CLOB
DISTRIBUTION VARCHAR2(30)
CPU_COST NUMBER(38)
IO_COST NUMBER(38)
TEMP_SPACE NUMBER(38)
ACCESS_PREDICATES VARCHAR2(4000)
FILTER_PREDICATES VARCHAR2(4000)
PROJECTION VARCHAR2(4000)
TIME NUMBER(38)
QBLOCK_NAME VARCHAR2(30)
Oracle Database también proporciona información sobre
cursores en memoria a través de varias vistas dinámicas (v$). Para que un usuario no privilegiado pueda acceder a estas vistas (o cualquier vista dinámica), es necesario llevar adelante cualquiera de estas tres opciones:
SQL> select * from v$sql_workarea;
select * from v$sql_workarea
*
ERROR at line 1:
ORA-00942: table or view does not exist
Para otorgar los privilegios al usuario (user1), en este ejemplo con usuario sys debemos ejecutar la siguiente sentencia:
Para el caso de una vista en particular:
SQL> grant select on v_$sql_workarea to user1;
Grant succeeded.
Rol SELECT_CATALOG_ROLE:
SQL> grant select_catalog_role to user1;
Grant succeeded.
- Otorgar privilegios de SELECT sobre las vistas base.
- Asignar el rol SELECT_CATALOG_ROLE.
- Asignar el privilegio de sistema SELECT ANY DICTIONARY
SQL> select * from v$sql_workarea;
select * from v$sql_workarea
*
ERROR at line 1:
ORA-00942: table or view does not exist
Para otorgar los privilegios al usuario (user1), en este ejemplo con usuario sys debemos ejecutar la siguiente sentencia:
Para el caso de una vista en particular:
SQL> grant select on v_$sql_workarea to user1;
Grant succeeded.
Rol SELECT_CATALOG_ROLE:
SQL> grant select_catalog_role to user1;
Grant succeeded.
Privilegio SELECT ANY DICTIONARY:
SQL> grant select any dictionary to user1;
Grant succeeded.
SQL>
desc v$sql_workarea
Name Type Nullable Default Comments
----------------------
------------ -------- ------- --------
ADDRESS RAW(8) Y
HASH_VALUE NUMBER Y
SQL_ID VARCHAR2(13) Y
CHILD_NUMBER NUMBER Y
WORKAREA_ADDRESS RAW(8) Y
OPERATION_TYPE VARCHAR2(20) Y
OPERATION_ID NUMBER Y
POLICY VARCHAR2(10) Y
ESTIMATED_OPTIMAL_SIZE
NUMBER Y
ESTIMATED_ONEPASS_SIZE
NUMBER Y
LAST_MEMORY_USED NUMBER Y
LAST_EXECUTION VARCHAR2(10) Y
LAST_DEGREE NUMBER Y
TOTAL_EXECUTIONS NUMBER Y
OPTIMAL_EXECUTIONS NUMBER Y
ONEPASS_EXECUTIONS NUMBER Y
MULTIPASSES_EXECUTIONS
NUMBER Y
ACTIVE_TIME NUMBER Y
MAX_TEMPSEG_SIZE NUMBER Y
LAST_TEMPSEG_SIZE NUMBER Y
Para obtener el plan
de ejecución de un cursor en memoria,
podemos consultar v$sql_plan.
SQL>
desc v$sql_plan
Name Type Nullable Default Comments
-----------------
-------------- -------- ------- --------
ADDRESS RAW(8) Y
HASH_VALUE NUMBER Y
SQL_ID VARCHAR2(13) Y
PLAN_HASH_VALUE NUMBER Y
CHILD_ADDRESS RAW(8) Y
CHILD_NUMBER NUMBER Y
TIMESTAMP DATE Y
OPERATION VARCHAR2(30) Y
OPTIONS VARCHAR2(30) Y
OBJECT_NODE VARCHAR2(40) Y
OBJECT# NUMBER Y
OBJECT_OWNER VARCHAR2(30) Y
OBJECT_NAME VARCHAR2(30) Y
OBJECT_ALIAS VARCHAR2(65) Y
OBJECT_TYPE VARCHAR2(20) Y
OPTIMIZER VARCHAR2(20) Y
ID NUMBER Y
PARENT_ID NUMBER Y
DEPTH NUMBER Y
POSITION NUMBER Y
SEARCH_COLUMNS NUMBER Y
COST NUMBER Y
CARDINALITY NUMBER Y
BYTES NUMBER Y
OTHER_TAG VARCHAR2(35) Y
PARTITION_START VARCHAR2(64) Y
PARTITION_STOP VARCHAR2(64) Y
PARTITION_ID NUMBER Y
OTHER VARCHAR2(4000) Y
DISTRIBUTION VARCHAR2(20) Y
CPU_COST NUMBER Y
IO_COST NUMBER Y
TEMP_SPACE NUMBER Y
ACCESS_PREDICATES
VARCHAR2(4000) Y
FILTER_PREDICATES
VARCHAR2(4000) Y
PROJECTION VARCHAR2(4000) Y
TIME NUMBER Y
QBLOCK_NAME VARCHAR2(30) Y
REMARKS VARCHAR2(4000) Y
OTHER_XML CLOB Y
Para estadísticas de ejecución por cada paso u operación de
un plan de ejecución de los cursores en caché (por ejemplo, número de filas
devueltas, número de bloques leídos, etc.), podemos consultar v$sql_plan_statistics.
SQL>
desc v$sql_plan_statistics
Name Type Nullable Default Comments
-------------------
------------ -------- ------- --------
ADDRESS RAW(8) Y
HASH_VALUE NUMBER Y
SQL_ID VARCHAR2(13) Y
PLAN_HASH_VALUE NUMBER Y
CHILD_ADDRESS RAW(8) Y
CHILD_NUMBER NUMBER Y
OPERATION_ID NUMBER Y
EXECUTIONS NUMBER Y
LAST_STARTS NUMBER Y
STARTS NUMBER Y
LAST_OUTPUT_ROWS NUMBER
Y
OUTPUT_ROWS NUMBER Y
LAST_CR_BUFFER_GETS
NUMBER Y
CR_BUFFER_GETS NUMBER Y
LAST_CU_BUFFER_GETS
NUMBER Y
CU_BUFFER_GETS NUMBER Y
LAST_DISK_READS NUMBER Y
DISK_READS NUMBER Y
LAST_DISK_WRITES NUMBER
Y
DISK_WRITES NUMBER Y
LAST_ELAPSED_TIME NUMBER
Y
ELAPSED_TIME NUMBER Y
Finalmente, para obtener un join de las tres vistas anteriores, podemos
consultar v$sql_plan_statistics_all.
SQL>
desc v$sql_plan_statistics_all
Name Type Nullable Default Comments
----------------------
-------------- -------- ------- --------
ADDRESS RAW(8) Y
HASH_VALUE NUMBER Y
SQL_ID VARCHAR2(13) Y
PLAN_HASH_VALUE NUMBER Y
CHILD_ADDRESS RAW(8) Y
CHILD_NUMBER NUMBER Y
TIMESTAMP DATE Y
OPERATION VARCHAR2(30) Y
OPTIONS VARCHAR2(30) Y
OBJECT_NODE VARCHAR2(40) Y
OBJECT# NUMBER Y
OBJECT_OWNER VARCHAR2(30) Y
OBJECT_NAME VARCHAR2(30) Y
OBJECT_ALIAS VARCHAR2(65) Y
OBJECT_TYPE VARCHAR2(20) Y
OPTIMIZER VARCHAR2(20) Y
ID NUMBER Y
PARENT_ID NUMBER Y
DEPTH NUMBER Y
POSITION NUMBER Y
SEARCH_COLUMNS NUMBER Y
COST NUMBER Y
CARDINALITY NUMBER Y
BYTES NUMBER Y
OTHER_TAG VARCHAR2(35) Y
PARTITION_START VARCHAR2(64) Y
PARTITION_STOP VARCHAR2(64) Y
PARTITION_ID NUMBER Y
OTHER VARCHAR2(4000) Y
DISTRIBUTION VARCHAR2(20) Y
CPU_COST NUMBER Y
IO_COST NUMBER Y
TEMP_SPACE NUMBER Y
ACCESS_PREDICATES VARCHAR2(4000) Y
FILTER_PREDICATES VARCHAR2(4000) Y
PROJECTION VARCHAR2(4000) Y
TIME NUMBER Y
QBLOCK_NAME VARCHAR2(30) Y
REMARKS VARCHAR2(4000) Y
OTHER_XML CLOB Y
EXECUTIONS NUMBER
Y
LAST_STARTS NUMBER Y
STARTS NUMBER Y
LAST_OUTPUT_ROWS NUMBER Y
OUTPUT_ROWS NUMBER Y
LAST_CR_BUFFER_GETS NUMBER Y
CR_BUFFER_GETS NUMBER Y
LAST_CU_BUFFER_GETS NUMBER Y
CU_BUFFER_GETS NUMBER Y
LAST_DISK_READS NUMBER Y
DISK_READS NUMBER Y
LAST_DISK_WRITES NUMBER Y
DISK_WRITES NUMBER Y
LAST_ELAPSED_TIME NUMBER Y
ELAPSED_TIME NUMBER Y
POLICY VARCHAR2(10) Y
ESTIMATED_OPTIMAL_SIZE
NUMBER Y
ESTIMATED_ONEPASS_SIZE
NUMBER Y
LAST_MEMORY_USED NUMBER Y
LAST_EXECUTION VARCHAR2(10) Y
LAST_DEGREE NUMBER Y
TOTAL_EXECUTIONS NUMBER Y
OPTIMAL_EXECUTIONS NUMBER Y
ONEPASS_EXECUTIONS NUMBER Y
MULTIPASSES_EXECUTIONS
NUMBER Y
ACTIVE_TIME NUMBER Y
MAX_TEMPSEG_SIZE NUMBER Y
LAST_TEMPSEG_SIZE NUMBER Y
Las estadísticas de ejecución para cada paso u operación del
plan de ejecución de los cursores en caché, se pueden observar en la vista v$sql_plan_monitor si la ejecución de la
sentencia es monitoreada. Podemos forzar el monitoreo utilizando el hint MONITOR.
SQL>
desc v$sql_plan_monitor
Name Type Nullable Default Comments
-----------------------
------------ -------- ------- --------
KEY NUMBER Y
STATUS VARCHAR2(19) Y
FIRST_REFRESH_TIME DATE Y
LAST_REFRESH_TIME DATE Y
FIRST_CHANGE_TIME DATE Y
LAST_CHANGE_TIME DATE Y
REFRESH_COUNT NUMBER Y
SID NUMBER Y
PROCESS_NAME VARCHAR2(5) Y
SQL_ID VARCHAR2(13) Y
SQL_EXEC_START DATE Y
SQL_EXEC_ID NUMBER Y
SQL_PLAN_HASH_VALUE NUMBER Y
SQL_CHILD_ADDRESS RAW(8) Y
PLAN_PARENT_ID NUMBER Y
PLAN_LINE_ID NUMBER Y
PLAN_OPERATION VARCHAR2(30) Y
PLAN_OPTIONS VARCHAR2(30) Y
PLAN_OBJECT_OWNER VARCHAR2(30) Y
PLAN_OBJECT_NAME VARCHAR2(30) Y
PLAN_OBJECT_TYPE VARCHAR2(20) Y
PLAN_DEPTH NUMBER Y
PLAN_POSITION NUMBER Y
PLAN_COST NUMBER Y
PLAN_CARDINALITY NUMBER Y
PLAN_BYTES NUMBER Y
PLAN_TIME NUMBER Y
PLAN_PARTITION_START VARCHAR2(64) Y
PLAN_PARTITION_STOP VARCHAR2(64) Y
PLAN_CPU_COST NUMBER Y
PLAN_IO_COST NUMBER Y
PLAN_TEMP_SPACE NUMBER Y
STARTS NUMBER Y
OUTPUT_ROWS NUMBER Y
IO_INTERCONNECT_BYTES NUMBER
Y
PHYSICAL_READ_REQUESTS NUMBER
Y
PHYSICAL_READ_BYTES NUMBER Y
PHYSICAL_WRITE_REQUESTS
NUMBER Y
PHYSICAL_WRITE_BYTES NUMBER
Y
WORKAREA_MEM NUMBER Y
WORKAREA_MAX_MEM NUMBER Y
WORKAREA_TEMPSEG NUMBER Y
WORKAREA_MAX_TEMPSEG NUMBER
Y
Pre-requisitos para utilizar EXPLAIN PLAN (privilegios)
Para utilizar la
instrucción EXPLAIN PLAN, debemos tener los privilegios necesarios para
insertar filas en la tabla de salida
(PLAN_TABLE) que hayamos especificado.
Lógicamente, también debemos tener los privilegios
necesarios para ejecutar la sentencia SQL
de la cual queramos obtener el
plan de ejecución. Si la instrucción SQL
accede a una vista, entonces debemos tener privilegios para acceder a las
tablas y vistas en las que se basa la vista. Si la vista se basa en otra vista
que se basan en tablas, debemos tener también privilegios para acceder tanto a
la otra vista como a sus tablas subyacentes.
Por otro lado, para
poder examinar el plan de ejecución producido por EXPLAIN PLAN, debemos
tener también los privilegios necesarios para consultar la tabla de salida
(output table).
La instrucción EXPLAIN PLAN es una instrucción DML y no una sentencia DDL, por lo tanto, Oracle Database no realiza
commit implícitamente de los cambios
realizados en la tabla por la sentencia EXPLAIN PLAN. Si queremos mantener las
filas generadas por un EXPLAIN PLAN en la “output table”, debemos realizar un
commit de la transacción que contiene la sentencia.
No hay comentarios:
Publicar un comentario