You are on page 1of 5

Como puedo usar el optimizador basado en costes para optimizar una consulta?

Categora Optimizacin
Nivel Medio
Autor JM

El optimizador basado en costes (Cost Based Optimizer, CBO) se introdujo en Oracle 7 y


se basa en calcular el coste de distintos planes de ejecucin y eligir para la ejecucin el
plan de ejecucin con menor coste. En su contra, est el optimizador basado en reglas
(Rules Based Optimizer, RBO), que se basa en una reglas prefijadas para decidir el plan
de ejecucin de una consulta.
Para calcular el coste de una consulta, el optimizador se basa en las estadsticas
almacenadas en el catlogo de Oracle, a travs de la instruccin:
ANALYZE [TABLE,INDEX] <object_name> [COMPUTE, ESTIMATE] STATISTICS;

Si no existen datos estadsticos para un objeto (por ejemplo, porque se acaba de crear), se
utilizarn valores por defecto. Adems, si los datos estadsticos est anticuados, se corre
el riesgo de calcular costes basados en estadsticas incorrectas, pudiendo ejecutarse
planes
de
ejecucin
que
a
priori
pueden
parecer
mejores.
Por esto, si se utiliza el optimizador basado en costes, es muy importante analizar los
objetos periodicamente (como parte del mantenimiento de la base de datos). Como las
estadsticas van evolucionando en el tiempo (ya que los objetos crecen o decrecen), el
plan de ejecucin se va modificando para optimizarlo mejor a la situacin actual de la
base de datos. El optimizador basado en reglas haca lo contrario: ejecutar siempre el
mismo plan, independientemente del tamao de los objetos involucrados en la consulta.
Dentro de la optimizacin por costes, existen dos modos de optimizacin, configurables
desde el parmetro OPTIMIZER_MODE:
- FIRST_ROWS: utiliza slo un nmero determinado de filas para calcular los planes de
ejecucin. Este mtodo es ms rpido pero puede dar resultados imprecisos.
- ALL_ROWS: utiliza todas las filas de la tabla a la hora de calcular los posibles planes
de ejecucin. Este mtodo es ms lento, pero asegura un plan de ejecucin muy preciso.
Si no se indica lo contrario, este es el mtodo por defecto.
El optimizador basado en costes se utilizar en alguna de las siguientes situaciones:
1.- Si el parmetro OPTIMIZER_MODE del archivo INIT.ORA est definido como
ALL_ROWS
o
FIRST_ROWS.
2.- Si existen estadsticas para alguna de las tablas involucradas en la consulta y el
parmetro
OPTIMIZER_MODE
es
distinto
a
RULE.
3.Si
se
incluye
un
"hint"
distinto
a
+RULE.
4.- Si se ha establecido la variable OPTIMIZER_GOAL a ALL_ROWS o FIRST_ROWS
a
nivel
de
sesin.
5.- En Oracle 7.3, si alguna tabla tiene un grado de paralelismo distinto de 0.

Cmo puedo saber el optimizador que est siendo usado?


Categora Optimizacin
Nivel Medio - bajo
Autor JM

Hay que generar un plan de ejecucin de la consulta a travs del comando EXPLAIN
PLAN. Una vez generado, se debe comprobar la columna POSITION de PLAN_TABLE
para aquellas filas que ID=0. Si el valor de POSITION es NULL, se est usando el
optimizador basado en reglas, en el resto de los casos se utiliza el basado en costes.
El siguiente SELECT nos puede servir para ver el tipo de optimizador utilizado en los
distintos planes:
SELECT
WHERE

DECODE(

NVL(position,-1),-1,
FROM

'Reglas','Costes')
plan_table

id = 0;

Como puedo averiguar el plan de ejecucin que utiliza una consulta?


Categora Optimizacin
Nivel Medio
Autor JM

Esto se puede hacer con distintos mtodos:


1.Activando
la
traza
de
SQL
a
nivel
de
2.Utilizando
la
instruccin
EXPLAIN
3.- Utilizando el comando SET AUTOTRACE de SQL*Plus.

sesin.
PLAN.

1.- Activar la traza de SQL a nivel de sessin:


Consultar el FAQ sobre trazas a nivel de sesin.
2.-Utilizar la instruccion EXPLAIN PLAN:
La instruccin EXPLAIN PLAN nos permite llenar la tabla PLAN_TABLE con datos
sobre el plan de ejecucin. La tabla PLAN_TABLE debe crearse, y para ello podemos ir
al fichero UTLXPLAN.SQL del directorio $ORACLE_HOME/rdbms/admin. Una vez
creada la tabla, ejecutaremos la instruccin:
[SET

STATEMENT

ID
INTO

EXPLAIN
PLAN
=
'identificador']
esquema.PLAN_TABLE

FOR <instruccion SQL>;

Con esto llenaremos la tabla PLAN_TABLE con un nmero de registros indeterminado.


Cada registro, tendr en la columna STATEMENT_ID el valor 'identificador'. Para ver el

plan de ejecucin, podremos mostrar las distintas filas formateadas con la siguiente
consulta:
SELECT

LPAD(

(level-1))

||

operation

FROM
WITH
id
=
statement_id
=
CONNECT
BY
PRIOR
id
=
statement_id = 'identificador';
START

operation,
options,
object_name,
output
0
AND
'identificador'
parent_id
AND

3.- Utilizar el comando AUTOTRACE (a partir de Oracle 7.3)


El programa SQL*Plus nos permite mostrar el plan de ejecucin de todas las
instrucciones que vamos lanzando. Para ello basta con activar la auto-traza a travs del
comando:
SET AUTOTRACE [ON,OFF] [EXPLAIN] [STATISTICS]

Si indicamos la opcin EXPLAIN, nos mostrar el plan de ejecucin, y si indicamos la


opcin STATISTICS, nos presentar una tabla de estardsticas tales como nmero de
ordenaciones, lecturas a disco, bloques recuperados, etc. Para poder ejecutar este
comando, es necesario tener el permisos sobre V$SESSION. La mejor manera de
conseguir esto es concediendo el rol completo PLUSTRACE, y estar creada la tabla
PLAN_TABLE dentro del esquema actual (ver el punto 2 para consultar cmo crear esta
tabla).

Cmo puedo obtener una traza de todas las sentencias ejecutadas durante una
sesin?
Categora Optimizacin
Nivel Alto
Autor JM

Oracle nos permite obtener una traza de todas las instrucciones que se lancen en una
sesin determinada. Puede ser til para ver el plan de ejecucin de cada una de ellas, para
averiguar las instrucciones SQL que son lanzadas contra una base de datos (cuando no
disponemos de los fuentes de un programa concreto), o incluso para detectar qu
instruccin ralentiza un proceso complejo.
Los pasos a dar son:
a) Obtener el 'sid' y 'serial#' del proceso sobre el que queremos hacer la traza. Para ello
debemos hacer la siguiente consulta sobre V$SESSION:
SELECT
ORDER BY 1, 2;

username,
FROM

program,

sid,

Dentro de la tabla resultado, buscaremos nuestro proceso, por ejemplo:

serial#
v$session

USERNAME
--------------SCOTT

PROGRAM
-------------------DELPHI32.EXE

---------

SID
9

SERIAL#
--------30

b) Ejecutar el siguiente bloque de cdigo PL/SQL:


BEGIN

SYS.DBMS_SYSTEM.set_sql_trace_in_session(9,

30,

TRUE);

END;

Esto nos activa la traza para una sesin identificada por sid y serial#
c) Ejecutar todas las instrucciones sobre las que queremos hacer la traza. Esto puede ser
una instruccin concreta, un proceso completo, o incluso una jornada entera de trabajo
con un programa.
d) Ejecutar de nuevo el bloque de cdigo para desactivar la traza:
BEGIN
END;

SYS.DBMS_SYSTEM.set_sql_trace_in_session(9,

30,

FALSE);

e) En el directorio configurado para la salida aparecer nuestro archivo de traza


ORAxxx.trc. Este directorio se configura desde la opcin USER_DUMP_DEST del
archivo INIT.ORA. Por defecto tiene el valor ORACLE_HOME/rdbms/trace.
f) Formatear el archivo de traza a travs de la utilidad TKPROF, situada en el directorio
BIN de la instalacin de Oracle. Una llamada bsica podra ser la siguiente:
TKPROF <fichero_traza> <fichero_salida> [explain=usuario/password]
[sys=no]

Con el parmetro "explain=usuario/password" indicamos que nos muestre el plan de


ejecucin de todas las instrucciones, conectndose para ello al usuario/password
indicados.
Con el parmetro "sys=no" indicamos que no nos muestre las instrucciones realizadas por
el usuario SYS.
Adems de las instrucciones y su plan de ejecucin, el archivo de traza nos proporciona
informacin sobre las sentencias erroneas, los tiempos de ejecucin, el optimizador
utilizado, etc.

Porqu una conversin en el WHERE desactiva mis ndices?


Categora Optimizacin
Nivel Medio - bajo
Autor JM

Cuando se hace una consulta y la condicin de filtro incluya una funcin de conversin
(TO_NUMBER, TO_DATE, etc.), esta se debe aplicar siempre que se pueda sobre un
valor
constante
en
vez
de
sobre
una
columna.
Por ejemplo, la siguiente consulta no utilizar ningn indice sobre

<COLUMNA_VARCHAR>
WHERE

FROM
TO_NUMBER(<COLUMNA_VARCHAR>) = 2;

Sin embargo, la siguiente


<COLUMNA_VARCHAR>

consulta

que

SELECT

utiliza

<COLUMNAS>
<TABLA>

los

SELECT
WHERE

FROM
<COLUMNA_VARCHAR> = TO_CHAR(2);

ndices

sobre

la

<COLUMNAS>
<TABLA>

Las conversiones implcitas siguen unas normas parecidas, pero teniendo en cuenta que
Oracle aplicar la funcin de conversin sobre el valor alfanumrico:
Por ejemplo, esta consulta:
FROM
WHERE

SELECT

<COLUMNAS>
<TABLA>

SELECT

<COLUMNAS>
<TABLA>

<COLUMNA_VARCHAR> = 2;

ser interpretada del siguiente modo:


WHERE

FROM
TO_NUMBER(<COLUMNA_VARCHAR>) = 2;

Por lo tanto, desactivar los ndices. Sin embargo, esta otra consulta:
SELECT

<COLUMNAS>
<TABLA>

SELECT
FROM
<COLUMNA_VARCHAR> = TO_NUMBER('2');

<COLUMNAS>
<TABLA>

FROM
WHERE

<COLUMNA_NUMBER> = '2';

ser interpretada del siguiente modo:


WHERE

Por lo que no desactivar los ndices, ya que la funcin se aplica sobre el valor constante
y no sobre la columna.

You might also like