Sei sulla pagina 1di 29

PERFORMANCE EN LAS CONSULTAS ORACLE

Operaciones que accesan tablas


ORACLE desarrolla dos tipos de operaciones para accesar filas de una
tabla:

 Acceso Total a la Tabla (TABLE ACCESS FULL)

Una Búsqueda Secuencial de Tabla Completa lee cada fila de una tabla.
Para optimizar la performance de una búsqueda de tabla completa, ORACLE lee
múltiples bloques durante cada lectura de la base de datos.
Una búsqueda completa a la tabla es utilizada siempre que no exista
cláusula where en una Consulta.

 Acceso a Tabla a través del ROWID (TABLE ACCESS BY ROWID)

Para mejorar la performance de acceso a las tablas, es posible usar esta


operación, que permite accesar la filas a través de los valores de la pseudocolumna
RowID. El RowID graba la ubicación física donde la fila es almacenada. ORACLE usa
índices para correlacionar los valores de dato con los valores de RowID – y así con las
ubicaciones físicas de los datos. Por lo que los índices proporcionan rápido acceso a
los valores de RowID, ellos ayudan a mejorar la performance de las consultas que
hacen uso de columnas indexadas.

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Seleccionar la Secuencia de Nombre de Tablas más Eficiente

ORACLE siempre procesa los nombres de tablas de derecha a izquierda,


de esta manera el nombre de tabla que se especifica al último es actualmente la
primera tabla procesada. Si se especifica mas de una tabla en la cláusula FROM de
una instrucción SELECT, se debe escoger la tabla con el menor número de filas hacia
más a la derecha. Cuando ORACLE procesa múltiples tablas, usa un procedimiento
interno de sort/merge para realizar el JOIN de dichas tablas. Primero se busca y se
ordena la primera tabla (la especificada al último de la cláusula FROM). Luego, se
busca en la segunda tabla y se mezclan todas las filas recuperadas desde la segunda
tabla con las recuperadas de la primera tabla.

Por Ejemplo:

La Tabla TAB1 tiene 16.384 filas.


La Tabla TAB2 tiene 1 fila.

Mejor Performance:
SELECT COUNT(*) FROM TAB1, TAB2 0.96
segundos

Peor Performance:
SELECT COUNT(*) FROM TAB2, TAB1 26.09
segundos

Si tres tablas están siendo relacionadas a través de un JOIN, se debe


seleccionar la tabla intersección como la tabla principal. La tabla intersección es aquella
que posee más tablas dependientes de ella.

Por Ejemplo:

La tabla EMP representa la intersección entre las tablas UBICACIÓN y


CATEGORIA.

SELECT . . .
FROM UBICACION U,
CATEGORÍA C,
EMP E
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.UBICA = U.UBICA

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Es más eficiente que:

SELECT . . .
FROM EMP E,
UBICACIÓN U,
CATEGORIA C
WHERE E.CAT_NO = C.CAT_NO
AND E.UBICA = L.UBICA
AND E.EMP_NO BETWEEN 1000 AND 2000

Posición de JOINS en la Cláusula WHERE

Los JOINS que relacionan Tablas debieran ser escritos primero que
cualquier condición de la cláusula WHERE. Y las condiciones que filtran el máximo de
registros debieran ser ubicadas al final de los JOINS.

Por Ejemplo:

Menos Eficiente : (Total CPU = 156.3 Seg.)

SELECT . . . .
FROM EMP E
WHERE SAL > 50000
AND JOB = ‘DIRECTOR’
AND 25 < (SELECT COUNT(*)
FROM EMP
WHERE MGR = E.EMPNO);

Más Eficiente : (Total CPU = 10.6 Seg.)

SELECT . . . .
FROM EMP E
WHERE 25 < (SELECT COUNT(*)
FROM EMP
WHERE MGR = E.EMPNO )
AND SAL > 50000
AND JOB = ‘DIRECTOR’;

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Uso del * en instrucciones SELECT
La referencia (*) entrega una manera de referenciar todas las columnas
de la tabla. No use la característica (*) porque es muy ineficiente ya que el * debe ser
convertido en cada columna. El análisis de todos los campos referenciados obteniendo
todos los nombres de columnas desde el diccionario de datos y sustituyéndolos en la
línea de comando, lo cual consume tiempo.

Reducción del Número de Accesos a la Base de Datos

Cada vez que una instrucción SQL es ejecutada, ORACLE necesita


desarrollar muchos procesos internos; las instrucciones necesitan ser analizadas,
índices evaluados, variables y bloques de datos leídos. Entre más sea posible reducir
los accesos a la Base de Datos, más gastos indirectos es posible ahorrar.

Por Ejemplo:

Existen tres diferentes maneras de recuperar datos acerca de los


empleados cuyos códigos son 0342 o 0291.

Método 1 (Menos Eficiente):

SELECT EMP_NAME, SALARY, GRADE


FROM EMP
WHERE EMP_NO = 0342;

SELECT EMP_NAME, SALARY, GRADE


FROM EMP
WHERE EMP_NO = 0291;

Método 2 (Eficiente):

DECLARE
CURSOR C1(E_NO NUMBER) IS
SELECT EMP_NAME, SALARY, GRADE
FROM EMP
WHERE EMP_NO = E_NO;
BEGIN
OPEN C1(342);
FETCH C1 INTO …, …, …;
....
Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
....

OPEN C1(291);
FETCH C1 INTO …, …, …;
CLOSE C1;
END;

Método 3 (Más Eficiente):

SELECT A.EMP_NAME, A.SALARY, A.GRADE,


B.EMP_NAME, B.SALARY, B.GRADE,
FROM EMP A,
EMP B
WHERE A.EMP_NO = 0342
AND B.EMP_NO = 0291;

Uso del DECODE para Reducir Procesamiento

La instrucción DECODE provee una manera de impedir tener que buscar


las mismas filas repetitivamente o hacer JOIN a la misma tabla repetitivamente.

Por Ejemplo:

SELECT COUNT(*), SUM(SAL)


FROM EMP
WHERE DEPT_NO = 0020
AND ENAME LIKE ‘SMITH%’;

SELECT COUNT(*), SUM(SAL)


FROM EMP
WHERE DEPT_NO = 0030
AND ENAME LIKE ‘SMITH%’;

Usted puede alcanzar el mismo resultado mucho más eficientemente con el DECODE:

SELECT COUNT(DECODE(DEPT_NO, 0020, ‘X’, NULL)) D0020_COUNT,


COUNT(DECODE(DEPT_NO, 0030, ‘X’, NULL)) D0030_COUNT,
SUM(DECODE(DEPT_NO, 0020, SAL, NULL)) D0020_SAL,
SUM(DECODE(DEPT_NO, 0030, SAL, NULL)) D0030_SAL
FROM EMP
WHERE ENAME LIKE ‘SMITH%’;

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
De manera similar, DECODE puede ser usado con GROUP BY u ORDER BY
efectivamente.
Combinando Accesos a Bases de Datos Simple y sin relación.

Si se está ejecutando un número de consultas simples de Bases de


Datos, es posible mejorar la performance combinándolas dentro de una sola consulta,
inclusive si ellas no están relacionadas.

Por Ejemplo:

SELECT NAME
FROM EMP
WHERE EMP_NO = 1234;

SELECT NAME
FROM DPT
WHERE DPT_NO = 10;

SELECT NAME
FROM CAT
WHERE CAT_TYPE = 'RD';

Las tres consultas anteriores pueden ser combinadas como se muestra a continuación:

SELECT E.NAME, D.NAME, C.NAME


FROM CAT C, DPT D, EMP E, DUAL X
WHERE NVL('X', X.DUMMY) = NVL('X', E.ROWID (+))
AND NVL('X', X.DUMMY) = NVL('X', D.ROWID (+))
AND NVL('X', X.DUMMY) = NVL('X', C.ROWID (+))
AND E.EMP_NO (+) = 1234
AND D.DEPT_NO (+) = 10
AND C.CAT_TYPE (+) = 'RD'

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Borrando Registros Duplicados

La manera eficiente de borrar registros duplicados desde una tabla es la


que se muestra a continuación. Es ventajoso dado que el ROWID de las filas tiene que
ser único.

DELETE FROM EMP E


WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X
WHERE X.EMP_NO = E.EMP_NO);

Uso de TRUNCATE en vez de DELETE

Cuando las filas son removidas desde una tabla, bajo circunstancias
normales, los segmentos de ROLLBACK son usados para almacenar información de
respaldo; si no se realiza COMMIT de la transacción, Oracle recupera los datos en el
mismo estado que se encontraban antes que la transacción comenzara.
Con TRUNCATE, ninguna información de respaldo es generada. Una vez
que la tabla ha sido truncada, los datos no pueden ser recuperados. Es más rápido y
necesita menos recursos.
Use TRUNCATE en vez de DELETE para limpiar los contenidos de tablas
pequeñas o grandes cuando no se necesita que se genere información de
recuperación.

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Ejecución Frecuente de Instrucciones COMMIT

Cuando sea posible, desarrolle frecuentemente instrucciones COMMIT en


todos sus programas. De esta manera la performance del programa es mejorada y sus
requerimientos de recursos son minimizados:

 Información almacenada en los segmentos de ROLLBACK para recuperar la


transacción, si es necesario.
 Todos los locks adquiridos durante el procesamiento de la instrucción.
 Espacio en el redo log buffer cache.

Contando Filas desde las Tablas


Contrario a la creencia popular, COUNT(*) es más rápido que COUNT(1).
Si las filas son recuperadas vía índice, se debe contar por la columna indexada. Por
ejemplo, COUNT(EMPNO) aún más rápido.

Uso del WHERE en lugar de HAVING


Evitar incluir una cláusula HAVING en instrucciones SELECT. La
cláusula HAVING filtra filas seleccionadas solamente después que todas la filas
han sido recuperadas. Esto puede incluir ordenamiento, resúmenes, etc. Restringir
filas via la cláusula WHERE, ayuda a reducir esta sobrecarga.

Por Ejemplo:

Menos Eficiente:

SELECT REGION, AVG(LOC_SIZE)


FROM LOCATION
GROUP BY REGION
HAVING REGION != ‘SYDNEY’
AND REGION != ‘PERTH’;

Más Eficiente:

SELECT REGION, AVG(LOC_SIZE)


FROM LOCATION
GROUP BY REGION
Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
WHERE REGION != ‘SYDNEY’
AND REGION != ‘PERTH’

Reducción al mínimo las Operaciones de Búsqueda de Tabla en una


Consulta
Para mejorar la performance, el número de operaciones de búsqueda en
las consultas, particularmente si las instrucciones incluyen sub-consultas SELECTs o
UPDATEs múltiples.

Por Ejemplo:

Menos Eficiente:
SELECT TAB_NAME
FROM TABLES
WHERE TAB_NAME = (SELECT TAB_NAME
FROM TAB_COLUMNS
WHERE VERSION = 604)
AND DB_VER = (SELECT DB_VER
FROM TAB_COLUMNS
WHERE VERSION = 604)

Más Eficiente:
SELECT TAB_NAME
FROM TABLES
WHERE (TAB_NAME, DB_VER) = (SELECT TAB_NAME, DB_VER
FROM TAB_COLUMNS
WHERE VERSION = 604)
Ejemplo de UPDATE Multicolumna:

Menos Eficiente :
UPDATE EMP
SET EMP_CAT = (SELECT MAX(CATEGORY)
FROM EMP_CATEGORIES),
SAL_RANGE = (SELECT MAX(SAL_RANGE)
FROM EMP_CATEGORIES )
WHERE EMP_DEPT = 0020;

Más Eficiente:

UPDATE EMP
SET (EMP_CAT, SAL_RANGE) = (SELECT MAX(CATEGORY), MAX(SAL_RANGE)

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
FROM EMP_CATEGORIES)
WHERE EMP_DEPT = 0020;

Reducir Sobrecarga de SQL vía uso de Funciones Almacenadas

SELECT H.EMPNO, E.ENAME,


H.HIST_TYPE, T.TYPE_DESC, COUNT(*)
FROM HISTORY_TYPE T, EMP E, EMP_HISTORY H
WHERE H.EMPNO = E.EMPNO
AND H.HIST_TYPE = T.HIST_TYPE
GROUP BY H.EMPNO, E.ENAME, H.HIST_TYPE, T.TYPE_DESC;

La performance de la instrucción anterior puede ser mejorada llamando a la función


que se llama a continuación:

FUNCTION Lookup_Hist_Type
(typ IN number) return varchar2
IS
tdesc varchar2(30);
CURSOR C1 IS
SELECT TYPE_DESC
FROM HISTORY_TYPE
WHERE HIST_TYPE = typ;
BEGIN
OPEN C1;
FETCH C1 INTO tdesc;
CLOSE C1;
return (NVL(tdesc, ’?’));
END;

FUNCTION Lookup_Emp
(emp IN number) return varchar2
IS
ename varchar2(30);
CURSOR C1 IS
SELECT ENAME
FROM EMP
WHERE EMPNO = emp;
BEGIN
OPEN C1;
FETCH C1 INTO ename;
CLOSE C1;
Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
return (NVL(ename, ’?’));
END;

SELECT H.EMPNO, Lookup_Emp(H.EMPNO),


H.HIST_TYPE, Lookup_Hist_Type(H.HIST_TYPE), COUNT(*)
FROM EMP_HISTORY H
GROUP BY H.EMPNO, H.HIST_TYPE;

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Uso de Alias de Tabla

Siempre use alias en las tablas y prefijo en todos los nombres de


columnas cuando es más de una tabla involucrada en una consulta. Esto reducirá el
tiempo de análisis y previene errores de sintaxis como la ambigüedad de nombres
entre columnas de la tabla.

Uso de EXISTS en lugar de IN


Muchas consultas de tabla base tienen actualmente JOIN con otra tabla
para satisfacer los criterios de selección. En tales casos, el EXISTS (o NOT EXISTS)
es a menudo una mejor opción. Además, EXISTS debiera utilizarse cuando la(s)
tabla(s) de la subconsulta recupere(n) gran cantidad de información.

Por Ejemplo:

Menos Eficiente:

SELECT *
FROM EMP (Tabla Base)
WHERE EMPNO > 0
AND DEPTNO IN (SELECT DEPTNO
FROM DEPT
WHERE LOC = ‘STGO’)

Más Eficiente:

SELECT *
FROM EMP
WHERE EMPNO > 0
AND EXISTS (SELECT ‘X’
FROM DEPT
WHERE DEPTNO = EMP.DEPTNO
AND LOC = ‘STGO’)

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Uso de NOT EXISTS en lugar de NOT IN
En subconsultas como las siguientes, la cláusula NOT IN causa un
sort/merge interno. La cláusula NOT IN es la más lenta posible, ya que fuerza una
lectura completa de la tabla en la subconsulta. Trate de no usar NOT IN y reemplácela
con Outer JOINS o con un NOT EXISTS como se muestra a continuación:

SELECT . . .
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO
FROM DEPT
WHERE DEPT_CAT = ‘A’);

Para mejorar la performance, reemplazar este código con:

Método 1 (Eficiente) :

SELECT . . .
FROM EMP A, DEPT B
WHERE A.DEPT_NO = B.DEPT_NO (+)
AND B.DEPT_NO IS NULL
AND B.DEPT_CAT(+) = 'A'

Método 2 (Más Eficiente) :

SELECT . . .
FROM EMP E
WHERE NOT EXISTS (SELECT ‘X’
FROM DEPT
WHERE DEPT_NO = E.DEPT_NO
AND DEPT_CAT = ‘A’);

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Uso JOINS en lugar del EXISTS

En general, relacionar tablas a través de JOIN más allá que especificar


subconsultas:

SELECT ENAME
FROM EMP E
WHERE EXISTS (SELECT ‘X’
FROM DEPT
WHERE DEPT_NO = E.DEPT_NO
AND DEPT_CAT = ‘A’);

Para mejorar la performance, especificar:

SELECT ENAME
FROM DEPT D, EMP E
WHERE E.DEPT_NO = D.DEPT_NO
AND D.DEPT_CAT = ‘A’;

Uso EXISTS en lugar de DISTINCT

Prevenir JOINS que requieren del DISTINCT en la lista del SELECT.

Por ejemplo:

Menos Eficiente:

SELECT DISTINCT DEPT_NO, DEPT_NAME


FROM DEPT D, EMP E
WHERE D.DEPT_NO = E.DEPT_NO

Más Eficiente:

SELECT DEPT_NO, DEPT_NAME

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
FROM DEPT D
WHERE EXISTS (SELECT ‘X’
FROM EMP E
WHERE E.DEPT_NO = D.DEPT_NO);

EXISTS es una alternativa más rápida porque el kernel del RDBMS


verifica que si la subconsulta se satisface una vez, la consulta puede ser terminada.

Uso de la Utilidad TKPROF para ver Estadísticas de Performance

La utilidad SQL Trace escribe un archivo de trace conteniendo


estadísticas de performance para las instrucciones SQL que están siendo ejecutadas.
El archivo de Trace provee importante información tales como ejecuciones y
recuperaciones desarrolladas, varios tipos de CPU y tiempos de respuesta, el número
de lectura físicas y lógicas, etc., que se puede usar para afinar el sistema.

Para activar el SQL trace, usar la siguiente instrucción:

ALTER SESSION SET SQL_TRACE TRUE

Para activar en forma global el SQL trace, se tiene que setear el parámetro
SQL_TRACE a TRUE en el init.ora. El parámetro USER_DUMP_DEST especifica el
directorio donde SQL trace escribe el archivo de trace.

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Uso de EXPLAIN PLAN para Analizar Instrucciones SQL

Explain Plan es una función Oracle que analiza la performance de


funciones SQL sin ejecutar la consultas primero. Los resultados del Explain Plan
entregan el orden en que Oracle ejecutará la búsqueda/JOIN de las tablas, los tipos de
los accesos que serán empleados (búsqueda indexada o búsqueda total de tabla), y los
nombre de los índices que serán usados.
Para utilizar Explain Plan, se debe tener creada la siguiente tabla en la
Base de Datos:

CREATE TABLE plan_table


(
statement_id VARCHAR2(30),
timestamp DATE,
remarks VARCHAR2(80),
operation VARCHAR2(30),
options VARCHAR2(30),
object_node VARCHAR2(128),
object_owner VARCHAR2(30),
object_name VARCHAR2(30),
object_instance NUMBER,
object_type VARCHAR2(30),
optimizer VARCHAR2(255),
search_columns NUMBER,
id NUMBER,
parent_id NUMBER,
position NUMBER,
other LONG
)

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Luego, se debe utilizar el siguiente script para ejecutar y ver el resultado
del Explain Plan. Se recomienda tener las instrucciones en un archivo con extensión
SQL.

set echo on
delete from plan_table
where statement_id = 'MI_QUERY';
commit;
COL operation FORMAT A30
COL options FORMAT A15
COL object_name FORMAT A20
EXPLAIN PLAN set statement_id = 'MI_QUERY' for
/* ------ Escriba su SQL Aqui ------*/
select *
from tabla
/*----------------------------*/
/
set echo off
select operation, options, object_name
from plan_table
where statement_id = 'MI_QUERY'
start with id = 0
connect by prior id=parent_id and prior statement_id =
statement_id;
set echo on

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Uso de Indices para mejorar la Performance

Un índice es una parte conceptual de una tabla de una base de datos que
puede ser usada para acelerar la recuperación de datos desde la tabla. Internamente,
ORACLE usa una sofisticada estructura de índice B-tree.

La recuperación indexada de datos desde una base de datos es casi


siempre más rápida que una búsqueda total a la tabla. ORACLE usa índices en el
desarrollo más eficiente de múltiples JOINS de múltiples tablas. Otro beneficio de los
índices es que ellos proveen una manera de garantizar la unicidad de la llave primaria
en una tabla.

Es posible indexar cualquier columna es una tabla excepto aquellas


definidas con tipos de datos LONG o LONG RAW. En general, los índices son más
útiles cuando ellos se especifican en tablas grandes. Si sobre tablas pequeñas se
realizan constantes JOINS también se encontrará mejora en la performance cuando se
indexe la tabla.

Aunque los índices usualmente proveen mejoras en la performance,


existe un costo de uso. Indices requieren espacio de almacenamiento. Ellos también
requieren mantención. Cada vez que un registro es agregado o borrado de una tabla y
cada vez que una columna indexada es modificada, los índices también deben
actualizarse. Esto puede significar cuatro o cinco accesos extras a disco por INSERT,
DELETE o UPDATE para un registro. Como los índices incurren en sobrecarga de
almacenamiento de datos y procesamiento, es posible degradar el tiempo de respuesta
si se especifican índices que no se utilizan.

El número máximo de índices se encuentra usualmente entre cuatro o


seis por tabla. Se debe mantener el número de índices sobre una tabla simple al
mínimo.

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Operaciones que usan Índices

ORACLE desarrolla dos operaciones para accesar los índices.

 Búsqueda por Índice Único (INDEX UNIQUE SCAN)

En la mayoría de los casos, el optimizador usa un índice via la cláusula


where de una consulta.

Por ejemplo:

Considerar una tabla LODGING teniendo dos índices en ella: un índice


único LODGING_PK en la columna Lodging y un índice no-único
LODGING$MANAGER en la columna Manager.

SELECT *
FROM LODGING
WHERE LODGING = ‘ROSE HILL’;

Internamente, la ejecución de la consulta será dividida en dos pasos.


Primero, el índice LODGING_PK será accesado vía una operación de Búsqueda Índice
Único. El valor de RowID que coincida con el valor ‘Rose Hill’ será retornado desde el
índice; este valor de RowID será usado para consultar LODGING vía una operación de
Acceso a Tabla a través de ROWID.
Si el valor requerido por la consulta está contenido dentro del índice,
entonces ORACLE no tendría necesidad de utilizar la operación Acceso a Tabla a
través de ROWID; puesto que los datos estarían en el índice, el índice tendría todo lo
necesario para satisfacer la consulta. Dado que la consulta selecciona todas las
columnas desde la tabla LODGING, y el índice no contiene todas las columnas de
dicha tabla, la operación de Acceso a Tabla se efectuará a través de RowID.
Las consultas mostradas requerirían solamente una operación de
búsqueda de índice único.

SELECT LODGING
Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
FROM LODGING
WHERE LODGING = ‘ROSE HILL’;

 BÚSQUEDA POR RANGO DE ÍNDICES

Si la consulta de base de datos está basada en un rango de valores, o si


la consulta usa un índice no único, entonces una operación de Búsqueda por Rango de
Índices usada para consultar el índice.

Ejemplo:

SELECT LODGING
FROM LODGING
WHERE LODGING LIKE ‘M%’

Al contener la cláusula Where un rango de valores, el índice único


LODGING_PK será accesado vía una operación de Búsqueda por Rango de Índice.
Como este tipo de operación requiere leer múltiples valores desde un índice, ellos son
menos eficientes que la Búsqueda de Índice Único. Aquí, la Búsqueda por Rango de
Índice de LODGING_PK es la única operación requerida para resolver la consulta,
como solamente la columna LODGING fue seleccionada por la consulta aquellos
valores son almacenados en el índice LODGING_PK que está siendo buscado.

Ejemplo:

SELECT LODGING
FROM LODGING
WHERE MANAGER = ‘BILL GATES’;

La consulta anterior se efectuará mediante dos operaciones: una


Búsqueda por Rango de Índice sobre LODGING$MANAGER (para obtener el valor de
RowID para todas aquellas filas con el valor ‘BILL GATES’ en la columna MANAGER),
seguida por un Acceso a Tabla a través del ROWID de la tabla LODGING (para
recuperar los valores de la columna LODGING). Dado que el índice
LODGING$MANAGER es un índice no único, la base de datos no puede desarrollar
una Búsqueda de Índice Único en el índice LODGING$MANAGER, inclusive si la
columna MANAGER es igualada a un valor simple en la consulta.

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Dado que la consulta selecciona la columna LODGING y la columna
LODGING no está en el índice LODGING$MANAGER, la Búsqueda por Rango de
Índice tiene que ser seguida por una operación de Acceso a Tablas a través de RowID.
Cuando se especifica una rango de valores para una columna, un índice
no será usado si el primer carácter especificado es un comodín. La siguiente consulta
no usará el índice LODGING$MANAGER:

SELECT LODGING
FROM LODGING
WHERE MANAER LIKE ‘%HANMAN’;

En este caso, una búsqueda de tabla completa (Operación de Acceso Completo a


Tabla) será desarrollada.

Selección de la Tabla Directiva.

La Tabla Directiva es la tabla que será leída primero (usualmente vía una
operación de Acceso Completo a la Tabla). El método de selección para la tabla
directiva depende del optimizador en uso.
Si se está usando CBO, entonces el optimizador chequeará las
estadísticas para el tamaño de tablas y la selección de los índices y escogerá la ruta
con el coste total más bajo.
Si se está usando RBO, y existen índices que están disponibles para
todas las condiciones de JOIN, entonces la tabla directiva será usualmente la que esté
listada al final de cláusula FROM.

Por Ejemplo:

SELECT A.NAME, B.MANAGER


FROM WORKER A,
LODGING B
WHERE A.LODGING = B.LODGING;

Dado que un índice está disponible sobre la columna LODGING de la


tabla LODGING, y no hay índice comparable disponible en la tabla WORKER, la tabla
WORKER será usada como la tabla directiva para la consulta.

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Deshabilitando Explícitamente un Índice

Si dos o mas índices tienen igual ranking, es posible forzar un índice


particular (que posee el menor número de filas que satisfacen la consulta) para ser
usado. Concatenando || ‘’ a una columna de tipo caracter ó + 0 a una columna
numérica suprime el uso del índice en dicha columna.

Por Ejemplo:

SELECT ENAME
FROM EMP
WHERE EMPNO = 7935
AND DEPTNO + 0 = 10
AND EMP_TYPE || ‘’ = ‘A’;

Aquí hay un ejemplo donde esta estrategia es justificada. Se supone que


se tiene un índice no único sobre la columna EMP_TYPE de la tabla EMP y que la
columna EMP_CLASS no está indexada:

SELECT ENAME
FROM EMP
WHERE EMP_TYPE = ‘A’
AND EMP_CLASS = ‘X’;

El optimizador notifica que EMP_TYPE está indexado y usa esta ruta; es


la única oportunidad en este punto. Si, un tiempo después, un segundo índice no único
es agregado sobre EMP_CLASS, el optimizador tendrá que escoger una ruta de
selección. Bajo circunstancias normales, el optimizador podría simplemente usar
ambas rutas, desarrollando un sort/merge en los datos resultantes. Mientras, si una
ruta particular es casi única (dado que retorna sólo 4 o 5 filas) y la otra ruta tiene miles
de duplicaciones, entonces la operación sort/merge es una sobrecarga innecesaria. En
este caso, se removerá el índice EMP_CLASS por consideraciones de optimización.
Es posible hacer esto escribiendo el SELECT de la siguiente manera:
Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
SELECT ENAME
FROM EMP
WHERE EMP_TYPE = ‘A’
AND EMP_CLASS || ‘’ = ‘X’;

Impedir Cálculos en Columnas Indexadas

Si la columna indexada es una parte de una función (en la cláusula


WHERE), el optimizador no usa un índice y desarrollará instantáneamente una
búsqueda completa de tabla.

Nota : Las funciones SQL MIN y MAX son excepciones a esta regla y utilizarán todos
los índices disponibles.

Por Ejemplo:

Menos Eficiente:
SELECT . . .
FROM DEPT
WHERE SAL * 12 > 25000;

Más Eficiente:

SELECT . . .
FROM DEPT
WHERE SAL > 25000 / 12;

Supresión Automática de Indices

Si una tabla tiene dos (o más) índices disponibles, y un índice es único y


el otro no, ORACLE usa la ruta de recuperación única e ignora completamente la
segunda opción.

Por Ejemplo:

SELECT ENAME
FROM EMP
WHERE EMPNO = 2362
Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
AND DEPTNO = 20;

Aquí, existe un único índice sobre EMPNO y un índice no único sobre


DEPTNO. El índice EMPNO es usado para recuperar la fila. El segundo predicado
(DEPTNO = 20) es evaluado (no se usa índice). El Explain Plan es como se muestra a
continuación:

TABLE ACCESS BY ROWID ON EMP


INDEX UNIQUE SCAN ON EMP_NO_IDX

Impedir es uso de NOT en Columnas Indexadas

En general, impedir el uso de NOT cuando se trabaja con columnas


indexadas. La función NOT tiene el mismo efecto en las columnas indexadas, es decir
NO usar el índice. Por lo anterior ORACLE realiza una búsqueda total en la tabla.

Por ejemplo:

Menos Eficiente: (Aquí, el índice no será usado)

SELECT . . .
FROM DEPT
WHERE DEPT_CODE NOT = 0;

Más Eficiente: (Aquí, el índice será usado)

SELECT . . .
FROM DEPT
WHERE DEPT_CODE > 0;

Uso de >= en vez de >

Existe un índice en la columna DEPTNO, entonces intente:

SELECT *
FROM EMP
WHERE DEPTNO >= 4

En vez de

SELECT *
Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
FROM EMP
WHERE DEPTNO > 3

Porque en vez de mirar en el índice para la primera fila con columna = 3 y


luego seguir buscando para encontrar el valor > 3, el DBMS puede saltar directamente
a la primera entrada que sea = 4.

Uso de UNION en lugar de OR (en caso de Columnas Indexadas)

En general, siempre use UNION en vez de OR en una cláusula WHERE.


Usando OR en una columna indexada causa que el optimizador desarrolle una
búsqueda de tabla completa en vez de una recuperación indexada. Note que
escogiendo UNION sobre OR será efectivo si ambas columnas se encuentran
indexadas;
En el siguiente ejemplo, ambas columnas LOC_ID y REGION están
indexadas.

SELECT LOC_ID, LOC_DESC, REGION


FROM LOCATION
WHERE LOC_ID = 10
UNION
SELECT LOC_ID, LOC_DESC, REGION
FROM LOCATION
WHERE REGION = ‘MELBOURNE’

En vez de:

SELECT LOC_ID, LOC_DESC, REGION


FROM LOCATION
WHERE LOC_ID = 10
OR REGION = ‘MELBOURNE’

Si se usa OR, hay que asegurarse de colocar el índice más específico en


primer lugar de la lista del predicado del OR, y colocar el índice que procesa más filas
al final de la lista.
Nótese lo siguiente:

WHERE KEY1 = 10 Debiera retornar menos filas


OR KEY2 = 20 Debiera retornar más filas
Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Es internamente traducido a:

WHERE KEY1 = 10
AND (KEY1 NOT = 10 AND KEY2 = 20)

Uso de IS NULL y IS NOT NULL en Columnas Indexadas

No se debe utilizar ninguna columna que contenga un NULL como parte


de un índice. ORACLE nunca puede usa un índice para buscar filas a través de
predicados que contengan IS NULL o IS NOT NULL.
En un índice de columna simple, si la columna es null, no hay entrada
dentro del índice.
Para índices compuestos, si cada parte de llave es null, no existe entrada
para el índice. Si al menos una columna de un índice compuesto es no nulo, existirá
una entrada al índice.

Por Ejemplo:

Menos Eficiente: (Aquí, el índice no será utilizado)

SELECT . . .
FROM DEPARTMENT
WHERE DEPT_CODE IS NOT NULL;

Más Eficiente: (Aquí, el índice será utilizado)

SELECT . . .
FROM DEPARTMENT
WHERE DEPT_CODE >= 0;

Siempre Usar la Columna Principal de un Índice Multicolumna

Si el índice es creado sobre múltiples columnas, entonces el índice


solamente será usado si la columna principal de él está siendo utilizada en una
cláusula where de la consulta. Si la consulta especifica valores para solamente las

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
columnas no principales del índice, entonces el índice no será usado para resolver la
consulta.

Operaciones Internas de Oracle

ORACLE desarrolla operaciones internas cuando ejecuta la consulta. La


siguiente tabla algunas de las más importantes operaciones que ORACLE desarrolla,
mientras ejecuta la consulta.

Cláusula Oracle Operaciones Internas de Oracle

ORDER BY SORT ORDER BY


UNION UNION-ALL
MINUS MINUS
INTERSECT INTERSECTION
DISTINCT, MINUS, INTERSECT, SORT UNIQUE
UNION
MIN, MAX, COUNT SORT AGGREGATE
GROUP BY SORT GROUP BY
ROWNUM COUNT o COUNT STOPKEY
Consultas que involucran JOINS SORT JOIN, MERGE JOIN, NESTED LOOPS
CONNECT BY CONNECT BY

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
Uso de UNION ALL en lugar de UNION (Cuando sea Posible)

Cuando las consultas desarrollan una UNION de resultados de dos


consultas, los dos conjuntos resultados son mezclados mediante la operación UNION
ALL, y luego el resultado es procesado a través de una operación SORT UNIQUE
antes que los registros sean retornados al usuario.
Si la consulta ha usado una función UNION-ALL en lugar de UNION,
entonces la operación SORT UNIQUE no debiera haber sido necesaria, así se mejora
el rendimiento de la consulta.

Por Ejemplo:

Menos Eficiente:

SELECT ACCT_NUM, BALANCE_AMT


FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = ‘31-DEC-95’
UNION
SELECT ACCT_NUM, BALANCE_AMT
FROM CREDIT_TRANSACTIONS
WHERE TRAN_DATE = ‘31-DEC-95’

Más Eficiente:

SELECT ACCT_NUM, BALANCE_AMT


FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = ‘31-DEC-95’
UNION ALL
SELECT ACCT_NUM, BALANCE_AMT
FROM CREDIT_TRANSACTIONS

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile
WHERE TRAN_DATE = ‘31-DEC-95’

Huérfanos 835 piso 20 oficina 2003, Fonos: * 6322497- *6322102, Fax: 6322529 - www.ciisa.cl
Santiago Chile

Potrebbero piacerti anche