You are on page 1of 52

OPTIMIZACIÓN DE CONSULTAS Y

SQL AVANZADO
CONTENIDO

1 INTRODUCCIÓN.......................................................................................................................................3
1.1 PROPÓSITO DEL DOCUMENTO................................................................................................................3
1.2 INTRODUCCIÓN AL STRUCTURED QUERY LANGUAGE ..........................................................................3
2 REVISIÓN DE CONCEPTOS BÁSICOS DE SQL.................................................................................4
2.1 COMPONENTES DEL SQL.......................................................................................................................4
2.2 CONSULTAS DE SELECCIÓN ..................................................................................................................4
2.3 CRITERIOS DE SELECCIÓN .....................................................................................................................6
2.4 AGRUPAMIENTO DE REGISTROS Y FUNCIONES AGREGADAS ................................................................7
2.5 CONSULTAS DE MANIPULACIÓN DE DATOS ...........................................................................................9
3 CONSULTAS DE UNIÓN INTERNAS (JOINS)...................................................................................11
3.1 CONSULTAS DE COMBINACIÓN ENTRE TABLAS ...................................................................................11
3.2 INNERS JOINS .......................................................................................................................................12
3.3 OUTER JOINS ........................................................................................................................................14
3.4 CONSULTAS DE AUTOCOMBINACIÓN ..................................................................................................15
3.5 CONSULTAS DE COMBINACIONES NO COMUNES .................................................................................16
4 CONSULTAS DE UNIÓN EXTERNAS (UNIONS) ..............................................................................17

5 SUBCONSULTAS.....................................................................................................................................19
5.1 EMPLEO DE SUBCONSULTAS................................................................................................................19
5.2 GRUPOS CON SUBCONSULTAS..............................................................................................................21
5.3 CASOS PRÁCTICOS ...............................................................................................................................22
6 OPTIMIZACIÓN DE CONSULTAS ......................................................................................................23
6.1 CONSEJOS GENERALES.........................................................................................................................23
6.2 EMPLEO DE ÍNDICES .............................................................................................................................25
6.3 SENTENCIAS CON JOINS. ......................................................................................................................31
6.4 SENTENCIAS CON SUBCONSULTAS.......................................................................................................32
6.5 VISTAS .................................................................................................................................................33
7 OPTIMIZACIÓN ORACLE: DATABASE TUNING ...........................................................................34
7.1 GENERALIDADES PARA LA OPTIMIZACIÓN DE SENTENCIAS SQL ........................................................34
7.2 TIPOS DE TABLAS ................................................................................................................................36
7.3 INDICES, TIPOS DE ÍNDICES..................................................................................................................42
7.4 PLAN DE EJECUCIÓN: INTERPRETACIÓN DE RESULTADOS...................................................................44
7.5 UTILIDADES DE INFORMACIÓN ESTADÍSTICA SOBRE LA EJECUCIÓN DE SENTENCIAS .........................45
7.6 ESTADÍSTICAS ......................................................................................................................................47
8 DICCIONARIO DE DATOS ORACLE..................................................................................................48

9 DICCIONARIO DE DATOS SQL SERVER .........................................................................................51

Página 2 de 52 © 2005 Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

1 Introducción
1.1 Propósito del Documento
El presente documento es una introducción que pretende establecer las normas para el mejor uso del gestor de Base
de Datos. Este conocimiento es fundamental para poder desarrollar procesos eficientes evitando cargas innecesarias al
sistema y aprovechando al máximo los recursos disponibles. El objetivo de este documento es, por tanto, servir de
guía a los desarrolladores que vayan a trabajar con Sql para que puedan desde un principio generar procesos
eficientes, ahorrando trabajos de ajuste posteriores.

Hay que recordar que por bueno que haya sido el trabajo de los DBA a la hora de crear y ajustar la base de datos en el
servidor, una aplicación ineficiente hará inútil todo este esfuerzo. El conseguir un rendimiento eficiente es, por tanto,
una tarea compartida de los administradores y los desarrolladores.

Los ejemplos se han tratado de orientar hacia los gestores de bases de datos Oracle y SQL Server.

1.2 Introducción al Structured Query Language


El lenguaje de consulta estructurado (SQL) es un lenguaje de base de datos normalizado (ANSI), utilizado por los
diferentes motores de bases de datos para realizar determinadas operaciones sobre los datos o sobre la estructura de
los mismos:

Es una forma estándar de consulta de datos específicos

Es una forma de extraer y manipular datos de una base de datos

Usado para todas las funciones de bases de datos, incluyendo administración, creación de esquemas y datos
recuperables

Puede ser usado de forma implícita dentro de una aplicación

Pero como sucede con cualquier sistema de normalización hay excepciones para casi todo; de hecho, cada motor de
bases de datos tiene sus peculiaridades y lo hace diferente de otro motor, por lo tanto, el lenguaje SQL normalizado
(ANSI) ha sido adaptado por los DBMS según peculiaridades, aunque si se puede asegurar que cualquier sentencia
escrita en ANSI será interpretable por cualquier motor de datos.

Página 3 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

2 Revisión de conceptos básicos de SQL

2.1 Componentes del SQL


El lenguaje SQL está compuesto por comandos, cláusulas, operadores y funciones de agregado. Estos elementos se
combinan en las instrucciones para crear, actualizar y manipular las bases de datos.

Comandos DLL: CREATE, DROP, ALTER

Comandos DML: SELECT, INSERT, UPDATE, DELETE,

Cláusulas: FROM, WHERE, GROUP BY, HAVING, ORDER BY

Operadores lógicos: AND, OR, NOT

Operadores de Comparación: < , >, <>, <=, >=, =, BETWEEN, LIKE, In

Funciones de Agregado: AVG, COUNT, SUM, MAX, MIN

2.2 Consultas de Selección


Las consultas de selección se utilizan para indicar al motor de datos que devuelva información de las bases de datos,
esta información es devuelta en forma de conjunto de registros.

2.2.1 Consultas Básicas


La sintaxis básica de una consulta de selección es la siguiente:

SELECT EmployeeID, LastName, FirstName FROM Employees;

En determinadas ocasiones nos puede interesar incluir una columna con un texto fijo en una consulta de selección:

SELECT ProductName, 'Precio unidad:', UnitPrice

FROM Products

WHERE CategoryID = 3;

2.2.2 Ordenar los Registros


Se puede especificar el orden en que se desean recuperar los registros de las tablas mediante la claúsula ORDER BY
Lista de Campos:

SELECT LastName, Address FROM Employees ORDER BY LastName;

Página 4 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

SELECT PostalCode, LastName, Address FROM Employees ORDER BY PostalCode, LastName DESC;

2.2.3 Consultas con Predicado


El predicado se incluye entre la claúsula y el primer nombre del campo a recuperar, los posibles predicados son:

* Devuelve todos los campos de la tabla

Distinct Omite los registros cuyos campos seleccionados coincidan totalmente

2.2.3.1 *
El Motor de base de datos selecciona todos los registros que cumplen las condiciones de la instrucción SQL.

SELECT * FROM Employees;

Tip: No conveniente abusar de él ya que obligamos al motor de la base de datos a analizar la estructura de la
tabla para averiguar los campos que contiene, es mucho más rápido indicar el listado de campos deseados.

2.2.3.2 Distinct
Omite los registros que contienen datos duplicados en los campos seleccionados.

SELECT DISTINCT LastName FROM Employees;

2.2.4 Alias
En determinadas circunstancias es necesario asignar un nombre a alguna columna determinada de un conjunto
devuelto. Para resolver todas ellas tenemos la palabra reservada AS que asigna el nombre que deseamos a la columna
deseada. AS no es una palabra reservada de ANSI.

También podemos asignar alias a las tablas dentro de la consulta de selección, en esta caso hay que tener en cuenta
que en todas las referencias que deseemos hacer a dicha tabla se ha de utilizar el alias en lugar del nombre.

SELECT LastName AS "Empleado" FROM Employees;

Tip: Esta nomenclatura [Tabla].[Campo] se debe utilizar cuando se está recuperando un campo cuyo nombre
se repite en varias de las tablas que se utilizan en la sentencia. Es aconsejable utilizar esta nomenclatura para
evitar el trabajo que supone al motor de datos averiguar en que tabla está cada uno de los campos indicados en
la cláusula SELECT.

Página 5 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

2.3 Criterios de Selección


Son las posibilidades de filtrar los registros con el fin de recuperar solamente aquellos que cumplan una condiciones
preestablecidas.

2.3.1 Operadores Lógicos


Los operadores lógicos soportados por SQL son: AND, OR, Is y Not. A excepción de los dos últimos todos poseen la
siguiente sintaxis:

<expresión1> operador <expresión2>

En donde expresión1 y expresión2 son las condiciones a evaluar.

Si a cualquiera de las anteriores condiciones le anteponemos el operador NOT el resultado de la operación será el
contrario al devuelto sin el operador NOT.

El operador denominado IS se emplea para comparar dos variables de tipo objeto <Objeto1> Is <Objeto2>. Este
operador devuelve Verdadero si los dos objetos son iguales.

SELECT * FROM Employees WHERE BirthDate > '1947-09-15' AND BirthDate < '1960-04-01';

SELECT * FROM Employees WHERE NOT City = 'London';

SELECT * FROM Employees WHERE (BirthDate > '1956-09-15' AND BirthDate < '1965-04-01') OR City =
'London' AND Title = 'Sales Manager';

2.3.2 Intervalos de Valores


Para indicar que deseamos recuperar los registros según el intervalo de valores de un campo emplearemos el operador
Between:

SELECT * FROM Products WHERE UnitPrice Between 50.0000 And 100.0000;

2.3.3 El Operador Like


Se utiliza para comparar una expresión de cadena con un modelo en una expresión SQL.

SELECT * FROM Products WHERE ProductName like 'M%'

2.3.4 El Operador In
Este operador devuelve aquellos registros cuyo campo indicado coincide con alguno de los en una lista:

SELECT * FROM Employees WHERE City In ('Seattle', 'Tacoma', 'Redmond');

Página 6 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

2.4 Agrupamiento de Registros y Funciones Agregadas


2.4.1 La cláusula GROUP BY
2.4.1.1 Agrupamiento de datos
SQL proporciona una forma eficiente para manejar la información con el agrupamiento de datos a través de la
formación de grupos y las funciones correspondientes, dando la posibilidad de procesar no solo registros individuales.
Cada grupo tendrá como resultado de la consulta una fila resumen que contiene la información del grupo.

Para la formación de grupos adicionamos, a la forma básica de la sentencia SELECT vista anteriormente, la orden
GROUP BY ubicada antes de ORDER BY, como se muestra a continuación:

SELECT Lista... FROM Tabla, Tabla... WHERE Condiciones

GROUP BY Expresión, Expresión,...

ORDER BY Expresión, Expresión,...;

Las funciones para el procesamiento de grupos son:

COUNT(columna) Cantidad de registros en que la columna tiene valores no nulos.

COUNT(*) Cantidad de registros que hay en la tabla, incluyendo los valores nulos.

MIN(columna) Valor mínimo del grupo.

MAX(columna) Valor máximo del grupo.

SUM(columna) Suma los valores del grupo.

AVG(columna) Calcula valor medio del grupo, sin considerar los valores nulos.

La lista de columnas a mostrar en la consulta puede contener las funciones de grupo, así como la columna o expresión
usada para formar los grupos en la orden GROUP BY. En una misma consulta no se pueden mezclar funciones de
grupo con columnas o funciones que trabajan con registros individuales.

GROUP BY es opcional. Los valores de resumen se omiten si no existe una función SQL agregada en la instrucción
SELECT.

Tip: Los valores Null en los campos GROUP BY se agrupan y no se omiten. No obstante, los valores Null no se
evalúan en ninguna de las funciones SQL agregadas.

Las cargas de pedidos por cliente es un buen ejemplo para mostrar el uso de los grupos:

SELECT CompanyName "CLIENTE",

COUNT(Freight) "CARGA",

Página 7 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

MIN(Freight) "MINIMA",

AVG(Freight) "MEDIA",

MAX(Freight) "MAXIMA",

SUM(Freight) "TOTAL"

FROM Customers,Orders

WHERE Customers.CustomerID=Orders.CustomerID

GROUP BY CompanyName;

Tip: El orden en las consultas por grupos, cuando no está presente la orden ORDER BY, está dado por la
columna que forma los grupos. Si deseamos cambiar ese orden, como es el caso de ordenar por el valor total de
ventas, se debe adicionar al final la orden ORDER BY SUM(VALOR).

SELECT CustomerID, COUNT(Freight) "CARGA",MIN(Freight) "MINIMA",

AVG(Freight) "MEDIA",MAX(Freight) "MAXIMA",SUM(Freight) "TOTAL"

FROM Orders

GROUP BY CustomerID ORDER BY SUM(Freight) DESC;

2.4.1.2 La cláusula having


Aplica una condición a los grupos después de formarse.Una vez que GROUP BY ha combinado los registros,
HAVING muestra cualquier registro agrupado por la cláusula GROUP BY que satisfaga las condiciones de la
cláusula HAVING.

HAVING es similar a WHERE, determina qué registros se seleccionan. Una vez que los registros se han agrupado
utilizando GROUP BY, HAVING determina cuales de ellos se van a mostrar.

SELECT ProductName, CategoryID, Sum(UnitsInStock) FROM Products GROUP BY CategoryID,


ProductName

HAVING Sum(UnitsInStock) < 100 AND ProductName Like 'Gra%';

Tip: Se utiliza la cláusula WHERE para excluir aquellas filas que no desea agrupar, y la cláusula HAVING
para filtrar los registros una vez agrupados.

2.4.2 Count (Contar registros)


Count cuenta el número de registros sin tener en cuenta qué valores se almacenan en los registros.

Página 8 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

SELECT Count(*) AS Total_Empleados FROM Employees;

SELECT Count(DISTINCT City) AS Total FROM Employees;

Tip: La función Count no cuenta los registros que tienen campos Null a menos que coloquemos el carácter
comodín asterisco (*). Si utiliza un asterisco, Count calcula el número total de registros, incluyendo aquellos
que contienen campos Null. Count(*) es considerablemente más rápida que Count(Campo).

2.4.3 Max y Min (Valores Máximos y Mínimos)


Devuelven el mínimo o el máximo de un conjunto de valores contenidos en un campo especifico de una consulta. Su
sintaxis es:

Min(expr) ó Max(expr)

Expr pueden incluir el nombre de un campo de una tabla, una constante o una función (la cual puede ser intrínseca o
definida por el usuario pero no otras de las funciones agregadas de SQL).

SELECT Min(UnitsInStock) AS stockMin FROM Products WHERE CategoryID = 1;

SELECT Max(UnitsInStock) AS stockMax FROM Products WHERE CategoryID = 1;

2.4.4 Sum (Sumar Valores)


Devuelve la suma del conjunto de valores contenido en un campo especifico de una consulta. Su sintaxis es:

Sum(expr)

En donde expr representa el nombre del campo que contiene los datos que desean sumarse o una expresión que
realiza un cálculo utilizando los datos de dichos campos.

SELECT Sum(UnitPrice * UnitsOnOrder) AS Total FROM Products;

2.5 Consultas de manipulación de datos


Las consultas de acción son aquellas que no devuelven ningún registro, son las encargadas de acciones como añadir y
borrar y modificar registros.

2.5.1 Delete
Elimina los registros de una o más de las tablas listadas en la cláusula FROM que satisfagan la cláusula WHERE.

DELETE FROM Region WHERE RegionDescription = 'Southern';

Página 9 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Tip: Una vez que se han eliminado los registros utilizando una consulta de borrado, no puede deshacer la
operación. Si desea saber qué registros se eliminarán, primero examine los resultados de una consulta de
selección que utilice el mismo criterio y después ejecute la consulta de borrado. Si elimina los registros
equivocados podrá recuperarlos desde las copias de seguridad.

2.5.2 Insert into


Agrega un registro en una tabla. Esta consulta puede ser de dos tipos: Insertar un único registro ó Insertar en una tabla
los registros contenidos en otra tabla.

Insertar un único registro:

INSERT INTO Tabla (campo1, campo2, .., campoN) VALUES (valor1, valor2, ..., valorN)

Para seleccionar registros e insertarlos en una tabla nueva

SELECT campo1, campo2, ..., campoN INTO nuevatabla FROM tablaorigen [WHERE criterios]

Insertar registros de otra tabla:

INSERT INTO Tabla [IN base_externa] (campo1, campo2, ..., campoN)

SELECT TablaOrigen.campo1, TablaOrigen.campo2, ..., TablaOrigen.campoN

FROM TablaOrigen

Si Tabla y TablaOrigen poseen la misma estrucutra podemos simplificar la sintaxis a:

INSERT INTO Tabla SELECT TablaOrigen.* FROM TablaOrigen

Tip: Con Oracle podemos crear una tabla a partir de una selección, insertando los datos implícitamente

CREATE TABLE Tabla1 AS SELECT * FROM Tabla2

2.5.3 Update
Crea una consulta de actualización que cambia los valores de los campos de una tabla especificada basándose en un
criterio específico.

UPDATE Employees SET ReportsTo = 1 WHERE ReportsTo = NULL;

UPDATE Products SET UnitPrice = UnitPrice * 1.1 WHERE SupplierID = 1 AND CategoryID = 2;

Si en una consulta de actualización suprimimos la cláusula WHERE todos los registros de la tabla señalada serán
actualizados.

UPDATE Products SET UnitPrice = UnitPrice * 1.1;

Página 10 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

3 Consultas de Unión Internas (Joins)

3.1 Consultas de Combinación entre tablas


La operación join permite extraer datos de dos o más tablas·

Join es la parte central del modelo relacional

Combina tablas en base a valores iguales de los renglones de cada tabla

Joins basados en la igualdad

Un registro en una tabla hace referencia a un registro en otra tabla, porque el contenido de las columnas de cada tabla
son iguales.

SELECT Suppliers.SupplierID, ProductName FROM Suppliers, Products

WHERE Suppliers.SupplierID = Products.SupplierID;

Consulta que muestra los productos que tiene cada proveedor.

Producto Cartesiano

Si no se especifican en el where las columnas utilizadas para relacionar las tablas, el sistema asume que se desea
obtener la combinación de los registros de cada tabla. Esto se conoce como producto cartesiano.

SELECT CompanyName, ProductName FROM Suppliers, Products;

Página 11 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

3.2 Inners Joins


Las vinculaciones entre tablas se realizan mediante la cláusula INNER que combina registros de dos tablas siempre
que haya concordancia de valores en un campo común. Su sintaxis es:

SELECT campos FROM tb1 INNER JOIN tb2 ON tb1.campo1 comp tb2.campo2

En donde:

tb1, tb2

Son los nombres de las tablas desde las que se combinan los registros.

campo1, campo2

Son los nombres de los campos que se combinan. Si no son numéricos, los campos deben ser del mismo tipo de datos
y contener el mismo tipo de datos, pero no tienen que tener el mismo nombre.

comp

Es cualquier operador de comparación relacional : =, <, >, <=, >=, o <>.

Se puede utilizar una operación INNER JOIN en cualquier cláusula FROM. Esto crea una combinación por
equivalencia, conocida también como unión interna. Las combinaciones de igualdad son las más comunes; éstas
combinan los registros de dos tablas siempre que haya concordancia de valores en un campo común a ambas tablas.

El ejemplo siguiente muestra cómo podría combinar las tablas Employees y Orders basándose en el campo
EmployeeID:

SELECT FirstName, ShipAddress

FROM Employees INNER JOIN Orders

ON Employees.EmployeeID = Orders.EmployeeID;

También se pueden enlazar varias cláusulas ON en una instrucción JOIN, utilizando la sintaxis siguiente:

SELECT campos

FROM tabla1 INNER JOIN tabla2

ON tabla1.campo1 comp tabla2.campo1 AND

ON tabla1.campo2 comp tabla2.campo2) OR

ON tabla1.campo3 comp tabla2.campo3)];

También puede anidar instrucciones JOIN utilizando la siguiente sintaxis:

Página 12 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

SELECT campos

FROM tabla1 INNER JOIN

(tabla2 INNER JOIN [( ] tabla3

[INNER JOIN [( ] tablaX [INNER JOIN ...)]

ON tabla3.campo3 comp tbx.campox)]

ON tabla2.campo2 comp tabla3.campo3)

ON tabla1.campo1 comp tabla2.campo2;

SELECT LastName, ShipAddress, CompanyName

FROM Customers INNER JOIN

(Orders INNER JOIN Employees

ON Orders.EmployeeID = Employees.EmployeeID)

ON Customers.CustomerID = Orders.CustomerID;

No obstante, los INNER JOIN ORACLE no es capaz de interpretarlos hasta la versión 8i, pero existe una
sintaxis en formato ANSI para los INNER JOIN que funcionan en todos los sistemas. Tomando como
referencia la siguiente sentencia:

SELECT Customers.CustomerId, Orders.freight, Orders.ShipCity

FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID

WHERE CompanyName = 'Franchi S.p.A.';

La transformación de esta sentencia a formato ANSI sería la siguiente:

SELECT Customers.CustomerId, Orders.freight, Orders.ShipCity

FROM Customers, Orders

WHERE Customers.CustomerID = Orders.CustomerID AND CompanyName = 'Franchi S.p.A.';

Página 13 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

3.3 Outer Joins


Si empleamos la cláusula INNER en la consulta se seleccionarán sólo aquellos registros de la tabla de la que hayamos
escrito a la izquierda de INNER JOIN que contengan al menos un registro de la tabla que hayamos escrito a la
derecha. Para solucionar esto tenemos dos cláusulas que sustituyen a la palabra clave INNER, estas cláusulas son
LEFT/RIGHT OUTER JOIN. LEFT toma todos los registros de la tabla de la izquierda aunque no tengan ningún
registro en la tabla de la izquierda. RIGHT realiza la misma operación pero al contrario, toma todos los registros de la
tabla de la derecha aunque no tenga ningún registro en la tabla de la izquierda.

SELECT DISTINCT Employees.EmployeeID, FirstName, ShipAddress, OrderID

FROM Employees Left outer JOIN Orders

ON Employees.EmployeeID = Orders.EmployeeID

order by employees.EmployeeID;

En este caso la consulta muestra todos los registros de la tabla Empleados (Employees) aunque no tengan ningún
registro asociado en la tabla Pedidos (Orders).

SELECT CompanyName, ShipAddress, OrderID

FROM Orders Right Outer JOIN Customers

ON Customers.CustomerID = Orders.CustomerID;

En este caso muestra todos los registros de la tabla Clientes (Customers) aunque no tengan ningún registro en la tabla
Pedidos (Orders). Puede haber clientes que no hayan realizado ningún pedido.

Referente a los OUTER JOIN, no funcionan en ORACLE hasta la versión 8i. La sintaxis en ORACLE se
emplea añadiendo los caracteres (+) detrás del nombre de la tabla en la que deseamos aceptar valores nulos,
esto equivale a un LEFT JOIN:

SELECT Facturas.*, Albaranes.* FROM Facturas, Albaranes

WHERE Facturas.IdAlbaran = Albaranes.IdAlbaran (+) AND Facturas.IdCliente = 325

Y esto a un RIGHT JOIN:

SELECT Facturas.*, Albaranes.* FROM Facturas, Albaranes

WHERE Facturas.IdAlbaran (+) = Albaranes.IdAlbaran AND Facturas.IdCliente = 325

Página 14 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Un LEFT JOIN o un RIGHT JOIN puede anidarse dentro de un INNER JOIN, pero un INNER JOIN no puede
anidarse dentro de un LEFT JOIN o un RIGHT JOIN.

Por ejemplo:

SELECT Products.ProductID, ProductName, CategoryName, OrderDetails.OrderID

FROM Categories INNER JOIN

(Products Left JOIN OrderDetails

ON Products.ProductID = OrderDetails.ProductID)

ON Categories.CategoryID = Products.CategoryID

order by Products.ProductID;

Crea dos combinaciones equivalentes: una entre las tablas Products y Categories, y la otra entre las tablas Products y
OrderDetails. La consulta retorna una lista de todos los productos existententes con su categoría correspondiente y
los pedidos realizados de dichos productos. En el caso de no existir ningún pedido relacionado a alguno de los
productos el campo OrderID aparecerá con valor NULL.

3.4 Consultas de Autocombinación


La autocombinación se utiliza para unir una tabla consigo misma, comparando valores de dos columnas con el mismo
tipo de datos. La sintaxis en la siguiente:

SELECT alias1.columna, alias2.columna, ...

FROM tabla1 as alias1, tabla1 as alias2

WHERE alias1.columna = alias2.columna

AND otras condiciones

Por ejemplo, para visualizar el número, nombre y puesto de cada empleado (EmployeeID, LastName, Title), junto
con el número, nombre y puesto del supervisor (ReportsTo, LastName, Title )de cada uno de ellos se utilizaría la
siguiente sentencia:

SELECT E.EmployeeID , E.LastName, E.Title, E.ReportsTo, S.LastName, S.Title

FROM Employees AS E, Employees AS S WHERE E.ReportsTo = S.EmployeeID;

El resultado de la consulta no mostrará a aquellos empleados los cuales no tengan asignados supervisor, es decir, en
aquellos casos para que ReportsTo = NULL.

UPDATE Employees SET TitleOfCourtesy = 'Sup.' WHERE EmployeeID NOT IN

Página 15 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

(SELECT E.EmployeeID FROM Employees AS E, Employees AS S

WHERE E.ReportsTo = S.EmployeeID);

Modifica el título de cortesía para aquellos empleados los cuales no dependen de ningún supervisor, es decir ellos
mismos son su propio supervisor.

3.5 Consultas de Combinaciones no Comunes


La mayoría de las combinaciones están basadas en la igualdad de valores de las columnas que son el criterio de la
combinación. Las no comunes se basan en otros operadores de combinación, tales como NOT, BETWEEN, <>, etc.

SELECT ProductName, CategoryID, Products.UnitPrice , Orders.OrderID, OrderDate, CustomerID

FROM Products,[Order Details] , Orders

WHERE OrderDate

BETWEEN '1996-07-01' AND '1996-07-30'

AND Products.ProductID = [Order Details].ProductID

AND [Order Details].OrderID = Orders.OrderID

ORDER BY Orders.OrderDate ASC;

La select muestra el nombre del producto, la categoría, el precio unitario del producto, el número de pedido, la fecha
de pedido y el ID del cliente que lo realizó, de todos los pedidos realizados entre el periodo comprendido entre ’01-
07-1996 y el 30-07-1996’ ambos inclusive. Ordenados por la fecha en que se realizó el pedido.

Página 16 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

4 Consultas de Unión Externas (Unions)


Se utiliza la operación UNION para crear una consulta de unión, combinando los resultados de dos o más consultas o
tablas independientes. Su sintaxis es:

[TABLE] consulta1 UNION [ALL] [TABLE]

consulta2 [UNION [ALL] [TABLE] consultan [ ... ]]

En donde: consulta1, consulta2, consultan

Son instrucciones SELECT, el nombre de una consulta almacenada o el nombre de una tabla almacenada precedido
por la palabra clave TABLE.

Puede combinar los resultados de dos o más consultas, tablas e instrucciones SELECT, en cualquier orden, en una
única operación UNION. El ejemplo siguiente combina una tabla existente llamada Nuevas Cuentas y una instrucción

SELECT:

TABLE [Nuevas Cuentas] UNION ALL SELECT * FROM Clientes

WHERE [Cantidad pedidos] > 1000;

Tip: Si no se indica lo contrario, no se devuelven registros duplicados cuando se utiliza la operación UNION,
no obstante puede incluir el predicado ALL para asegurar que se devuelven todos los registros. Esto hace que
la consulta se ejecute más rápidamente. Todas las consultas en una operación UNION deben pedir el mismo
número de campos, no obstante los campos no tienen porqué tener el mismo tamaño o el mismo tipo de datos.

Se puede utilizar una cláusula GROUP BY y/o HAVING en cada argumento consulta para agrupar los datos
devueltos. Puede utilizar una cláusula ORDER BY al final del último argumento consulta para visualizar los datos
devueltos en un orden específico.

SELECT [CompanyName], City FROM Suppliers WHERE Country = 'USA'

UNION SELECT [CompanyName], City FROM Customers WHERE Country = 'USA';

Recupera los nombres (CompanyName) y las ciudades (City) de todos proveedores (Suppliers) y clientes
(Customers) de USA.

SELECT [CompanyName], City FROM Suppliers WHERE

Country = 'USA' UNION SELECT [CompanyName], City FROM Customers

WHERE Country = 'USA' ORDER BY City;

Página 17 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Recupera los nombres (CompanyName) y las ciudades (City) de todos proveedores (Suppliers) y clientes
(Customers) de USA., ordenados por el nombre de la ciudad (City).

SELECT [CompanyName], City FROM Suppliers WHERE

Country = 'USA' UNION SELECT [CompanyName], City FROM Customers

WHERE Country = 'USA'

UNION SELECT [LastName], City FROM Employees WHERE Region ='WA';

Recupera los nombres (CompanyName) y las ciudades (City) de todos proveedores (Suppliers) y clientes
(Customers) de USA, y los apellidos (LastName) y ciudades (City) de todos los empleados cuya región es WA.

Página 18 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

5 Subconsultas

5.1 Empleo de Subconsultas


Una Subconsulta es aquella consulta de cuyo resultado depende otra consulta, llamada principal, y se define como
una sentencia SELECT que está incluida en la orden WHERE de la consulta principal. Una subconsulta, a su vez,
puede contener otra subconsulta y así hasta un máximo de 16 niveles.

Tip: Las consultas normalmente son ineficientes, por tanto deberán utilizarse como último recurso ya que
siempre es mejor tratar de realizar las consultas mediantes joins

Las subconsultas son usadas:

Porque algunas veces son más fáciles de entender que un join.

Para efectuar algunas tareas que en otro caso sería imposible realizar utilizando un join (por ejemplo usar una
función agregada)

Las particularidades de las subconsultas son:

Su resultado no se visualiza, sino que se pasa a la consulta principal para su comprobación.

Puede devolver un valor único o una lista de valores y en dependencia de esto se debe usar el operador del tipo
correspondiente.

No puede usar el operador BETWEEN, ni contener la orden ORDER BY.

Puede contener una sola columna, que es lo más común, o varias columnas. Este último caso se llama
subconsulta con columnas múltiples. Cuando dos o más columnas serán comprobadas al mismo tiempo, deben
encerrarse entre paréntesis.

Tip: Una subconsulta es una instrucción SELECT anidada dentro de una instrucción SELECT,
SELECT...INTO, INSERT...INTO, DELETE, o UPDATE o dentro de otra subconsulta.

Se puede utilizar una subconsulta en lugar de una expresión en la lista de campos de una instrucción SELECT o en
una cláusula WHERE o HAVING. En una subconsulta, se utiliza una instrucción SELECT para proporcionar un
conjunto de uno o más valores especificados para evaluar en la expresión de la cláusula WHERE o HAVING.

El predicado IN se emplea para recuperar únicamente aquellos registros de la consulta principal para los que algunos
registros de la subconsulta contienen un valor igual. El ejemplo siguiente devuelve todos los productos vendidos con
un descuento igual o mayor al 25 por ciento:

SELECT * FROM Orders WHERE OrderID IN

(SELECT OrderID FROM OrderDetails WHERE Discount >= 0.25);

Página 19 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Inversamente se puede utilizar NOT IN para recuperar únicamente aquellos registros de la consulta principal para los
que no hay ningún registro de la subconsulta que contenga un valor igual.

El predicado EXISTS (con la palabra reservada NOT opcional) se utiliza en comparaciones de verdad/falso para
determinar si la subconsulta devuelve algún registro. Supongamos que deseamos recuperar todos aquellos clientes
que hayan realizado al menos un pedido:

SELECT Customers.CompanyName, Customers.Phone FROM Customers WHERE EXISTS

(SELECT Orders.CustomerId FROM Orders WHERE Orders.CustomerId = Customers.CustomerId)

Esta consulta es equivalente a esta otra:

SELECT Customers.CompanyName, Customers.Phone FROM Customers WHERE CustomerId IN

(SELECT Orders.CustomerId FROM Orders)

Tip: Es útil utilizar también alias del nombre de la tabla en una subconsulta para referirse a tablas listadas en
la cláusula FROM fuera de la subconsulta.

SELECT ProductName, UnitPrice FROM Products AS T1

WHERE UnitPrice >= (SELECT Avg(UnitPrice) FROM Products

WHERE T1.ProductName = Products.ProductName)

ORDER BY ProductName;

Que también puede escribirse:

SELECT ProductName, UnitPrice FROM Products

WHERE UnitPrice >= (SELECT Avg(UnitPrice) FROM Products as T2

WHERE T2.ProductName = Products.ProductName)

ORDER BY ProductName;

Selecciona el nombre de todos los empleados que han reservado al menos un pedido.

SELECT FirstName, LastName FROM Employees AS E

WHERE EXISTS (SELECT * FROM Orders AS O WHERE O.EmployeeID = E. EmployeeID);

Página 20 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Obtiene una lista con el nombre y el precio unitario de todos los productos con el mismo precio que el producto
Chang.

SELECT DISTINCT Products.ProductName, Products.UnitPrice

FROM Products

WHERE Products.UnitPrice =(SELECT Products.UnitPrice FROM Products WHERE

Products.productName = 'Chang')

Supongamos que en nuestra tabla de empleados deseamos buscar todos los empleados cuyas edades superen a la
media de la compañía:

SELECT T1.FirstName FROM Employees T1

WHERE Year(T1.BirthDate) > (SELECT avg(Year(Employees.BirthDate))FROM Employees)

5.2 Grupos con subconsultas


Para combinar grupos con subconsultas debemos incluir en la sentencia SELECT la orden HAVING, que tiene las
siguientes características:

Funciona como la orden WHERE, pero sobre los resultados de las funciones de grupo, en oposición a las
columnas o funciones para registros individuales que se seleccionan mediante la orden WHERE. O sea, trabaja
como si fuera una orden WHERE, pero sobre grupos de registros.

Se ubica después de la orden GROUP BY.

Puede usar una función de grupo diferente a la de la orden SELECT.

El ejemplo a diseñar para nuestra aplicación es la consulta ¿cuál fue el artículo más vendido y en qué cantidad?. En
este caso, la orden HAVING de la consulta principal selecciona aquellos artículos (GROUP BY) que tienen una venta
total (SUM(valor)) igual a la mayor venta realizada por artículo (MAX(SUM(valor))) que devuelve la subconsulta.

SELECT column, SUM(column) FROM

GROUP BY column

HAVING SUM(column) condition value

En el ejemplo se seleccionan las unidades en stock del producto más caro:

Página 21 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

SELECT ProductName AS Producto, UnitsinStock AS StockActual FROM Products

GROUP BY ProductName, UnitsinStock, UnitPrice

HAVING UnitPrice =( Select MAX(UnitPrice) from Products)

5.3 Casos Prácticos

Búsqueda de registros duplicados

SELECT DISTINCTROW Lista de Campos a Visualizar FROM Tabla

WHERE CampoDeBusqueda In (SELECT CampoDeBusqueda FROM Tabla As pseudónimo

GROUP BY CampoDeBusqueda HAVING Count(*)>1 ) ORDER BY CampoDeBusqueda;

Un caso práctico, si deseamos localizar aquellos empleados con igual nombre y visualizar su código
correspondiente, la consulta sería la siguiente:

SELECT DISTINCT Employees.FirstName, Employees.EmployeeId

FROM Employees WHERE Employees.FirstName In (SELECT FirstName FROM

Employees As Tmp GROUP BY FirstName HAVING Count(*)>1)

ORDER BY Employees.FirstName;

Búsqueda de registros no relacionados

Este tipo de consulta se emplea en situaciones tales como saber qué productos no se han vendido.

SELECT DISTINCT Products.ProductId, Products.ProductName FROM Products

Left JOIN OrderDetails ON Orderdetails.ProductId = Products.ProductId

WHERE (Orderdetails.ProductId Is Null);

La sintaxis es sencilla, se trata de realizar una unión interna entre dos tablas seleccionadas mediante un LEFT
JOIN, estableciendo como condición que el campo relacionado de la segunda sea Null.

Página 22 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

6 Optimización de consultas
El lenguaje SQL es no procedimental, es decir, en las sentencias se indica que queremos conseguir y no como lo tiene
que hacer el interprete para conseguirlo. Esto es sólo teoría, pues en la práctica a todos los gestores de SQL hay que
especificar sus propias reglas para optimizar el rendimiento.

Por tanto, muchas veces no basta con especificar una sentencia SQL correcta, sino que además, hay que indicarle
como tiene que hacerlo si queremos que el tiempo de respuesta sea el mínimo. En este apartado veremos como
mejorar el tiempo de respuesta de nuestro interprete ante unas determinadas situaciones:

6.1 Consejos generales


La construcción de una sentencia y los operadores y condiciones empleados determinan como la interpreta el
analizador y por tanto su plan de ejecución. En muchos casos, la reescritura de una sentencia puede cambiar
radicalmente su plan de ejecución y su rendimiento en el sistema.

Como norma más general, una sentencia está optimizada cuando implica realizar el número más pequeño posible de
accesos a los datos.

Hay que procurar que las condiciones de la cláusula WHERE sean lo más restringidas posibles; debemos evitar
accesos a filas innecesarias.

Hay que especificar siempre las columnas a las que queremos acceder (No hacer nunca SELECT *...) evitando
así recuperar columnas que luego no utilizaremos y por que el gestor debe leer primero la estructura de la tabla
antes de ejecutar la sentencia.

En la medida de lo posible hay que evitar que las sentencias SQL estén embebidas dentro del código de la aplicación.
Es mucho más eficaz usar vistas o procedimientos almacenados por que el gestor los guarda compilados. Si se trata
de una sentencia embebida el gestor debe compilarla antes de ejecutarla.

Tip: Si utilizamos varias tablas en la consulta, especificar siempre a que tabla pertenece cada campo, le
ahorraremos al gestor el tiempo de localizar a que tabla pertenece el campo.

En lugar de:

SELECT Nombre, Factura FROM Clientes, Facturacion WHERE IdCliente = IdClienteFacturado

Usar :

SELECT Clientes.Nombre, Facturacion.Factura WHERE Clientes.IdCliente = Facturacion.IdClienteFacturado.

6.1.1 Diseño de las tablas


La optimización pasa por un correcto diseño del modelo de datos (Tablas), se deben seguir los siguientes consejos:

Página 23 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Normalizar las tablas, al menos hasta la tercera forma normal, para asegurar que no hay duplicidad de datos y se
aprovecha al máximo el almacenamiento en las tablas. Si hay que desnormalizar alguna tabla pensar en la
ocupación y en el rendimiento antes de proceder.

Los primeros campos de cada tabla deben ser aquellos campos requeridos y dentro de los requeridos primero se
definen los de longitud fija y después los de longitud variable.

Ajustar al máximo el tamaño de los campos para no desperdiciar espacio.

Es muy habitual dejar un campo de texto para observaciones en las tablas. Si este campo se va a utilizar con poca
frecuencia o si se ha definido con gran tamaño, por si acaso, es mejor crear una nueva tabla que contenga la clave
primaria de la primera y el campo para observaciones.

6.1.2 Campos de Filtro


Se procurará elegir en la cláusula WHERE aquellos campos que formen parte de la clave de la tabla por el cual
interrogamos. Además se especificarán en el mismo orden en el que estén definidos en la clave.

Tip: Interrogar siempre por campos que sean clave.

Si deseamos interrogar por campos pertenecientes a índices compuestos es mejor utilizar todos los campos de todos
los índices. Supongamos que tenemos un índice formado por el campo NOMBRE y el campo APELLIDO y otro
índice formado por el campo EDAD. La sentencia WHERE NOMBRE='Juan' AND APELLIDO Like '%' AND
EDAD = 20 sería más optima que WHERE NOMBRE = 'Juan' AND EDAD = 20 por que el gestor, en este segundo
caso, no puede usar el primer índice y ambas sentencias son equivalentes porque la condición APELLIDO Like '%'
devolvería todos los registros.

6.1.3 Orden de las Tablas


Cuando se utilizan varias tablas dentro de la consulta hay que tener cuidado con el orden empleado en la clausula
FROM. Si deseamos saber cuantos alumnos se matricularon en el año 1996 y escribimos: FROM Alumnos,
Matriculas WHERE Alumno.IdAlumno = Matriculas.IdAlumno AND Matriculas.Año = 1996 el gestor recorrerá
todos los alumnos para buscar sus matriculas y devolver las correspondientes. Si escribimos FROM Matriculas,
Alumnos WHERE Matriculas.Año = 1996 AND Matriculas.IdAlumno = Alumnos.IdAlumnos, el gestor filtra las
matrículas y después selecciona los alumnos, de esta forma tiene que recorrer menos registros.

6.1.4 Valores NULL


Con los valores Null debemos tener en cuenta las siguientes premisas:

Un valor NULL es un valor desconocido

Un Null no implica un cero o un espacio en blanco; es un valor que significa “información no disponible”·

Is Null debe ser utilizado para determinar valores Null contenidos en una columna; la sintaxis “= Null” es válida
pero no recomendada

Un valor Null nunca es igual a otro valor Null

Página 24 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Los valores Null se consideran en el ordenamiento y en los grupos, Algunas columnas son definidas para permitir
valores NULL

Si un elemento es Null en una operación el resultado será Null

6.2 Empleo de índices


Los índices son campos elegidos arbitrariamente por el constructor de la base de datos que permiten la búsqueda a
partir de dicho campo a una velocidad notablemente superior. Sin embargo, esta ventaja se ve contrarrestada por el
hecho de ocupar mucha más memoria (el doble más o menos) y de requerir para su inserción y actualización
un tiempo de proceso superior.

Un caso en el que los índices pueden resultar muy útiles es cuando realizamos peticiones simultáneas sobre varias
tablas. En este caso, el proceso de selección puede acelerarse sensiblemente si indexamos los campos que sirven de
nexo entre las dos tablas.

Los índices pueden resultar contraproducentes si los introducimos sobre campos triviales a partir de los cuales no se
realiza ningún tipo de petición ya que, además del problema de memoria ya mencionado, estamos ralentizando otras
tareas de la base de datos como son la edición, inserción y borrado. Es por ello que vale la pena pensárselo dos
veces antes de indexar un campo que no sirve de criterio para búsquedas o que es usado con muy poca frecuencia por
razones de mantenimiento.

La mayoría de consultas se optimizan si acceden a través de un índice. Ante una sentencia que no realice un acceso
por índice y que consideremos ineficiente se ha de considerar el introducir un índice en la base, y si éste ya existe,
averiguar porqué no lo utiliza y reescribir la sentencia para que lo haga. En relación a todo esto, hay que tener en
cuenta las siguientes consideraciones:

Utilizar índice para consultas muy restrictivas. El volumen máximo de datos recuperados sería del orden del 15 -
20 % de los registros de la tabla.

Para esto hay que conocer siempre el volumen (no es igual el 20 % de una tabla de 1M registros que de una tabla
de 20M registros) , naturaleza y distribución de los datos a tratar (una sentencia que funciona bien con algunos
valores puede ser inadmisible si hay un valor muy mayoritario), sin olvidar las previsiones de crecimiento; en
este sentido, la información de una base de desarrollo puede ser totalmente errónea, la aplicación se tiene que
ajustar con una carga de datos realista.

Referenciar la columna o columnas del índice en la cláusula WHERE. El analizador no utilizará índice en caso
contrario.

Se debe tratar que los índice tengan la mayor selectividad posible (es decir el número de filas obtenido por cada
valor del clave del índice). A mayor selectividad del índice mayor probabilidad de que sea usado por el
optimizador de consultas.

Se deben usar los índices con moderación, es decir, unos pocos índices pueden ser útiles pero demasiados
índices pueden afectar negativamente al rendimiento porque hay que mantenerlos actualizados cada vez que se
realizan operación de inserción, actualización y borrado en los datos.

Página 25 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

No poner índices en tablas pequeñas.

No podemos indexar todos los campos de una tabla extensa ya que doblaríamos el tamaño de la base de datos.
Igualmente.

Utilizar el menor número posible de columnas en el índice (índices estrechos), ya que estos ocupan menos
espacio y necesitan menos sobrecarga de mantenimiento.

Las referencias de las columnas de un índice compuesto en la cláusula WHERE tienen que estar en el mismo
orden que en el índice. No es obligatorio incluir condiciones sobre todas, pero sí sobre la primera, y si hay más
condiciones deberían ir sobre las siguientes columnas en el orden del índice. Lo ilustraremos con un ejemplo:

(Índice: NUM_CLIENTE, NOMBRE_CLIENTE, FECHA_ENTRADA)

El Analizador utilizará el índice con una cláusula WHERE de la forma:

NUM_CLIENTE = valor AND

NOMBRE_CLIENTE = valor AND

FECHA_ENTRADA = valor

Ó la siguiente:

NUM_CLIENTE = valor AND

NOMBRE_CLIENTE = valor

Ó la siguiente:

NUM_CLIENTE = valor

Ó la siguiente:

NUM_CLIENTE = valor AND

FECHA_ENTRADA = valor

En cambio NO utilizará el índice si el WHERE contiene:

NOMBRE_CLIENTE = valor AND

FECHA_ENTRADA = valor

Tampoco utilizará cuando:

NOMBRE_CLIENTE = valor

Página 26 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

No modificar la columna del índice en el WHERE con funciones o expresiones. Esto deshabilita el uso del
índice. Por ejemplo, no se usarían índice condiciones en el WHERE de la forma:

SUBSTR(NOMBRE, 1, 5) = ...

CLIENTE||'_01' = ...

TO_CHAR(FECHA_ENTRADA, 'DD/MM/YYYY')=...;

Notar que podemos encontrar casos tan sencillos como los siguientes:

(Índice 1: SUELDO ; Índice 2: NOMBRE)

SELECT SUELDO FROM EMPLEADOS WHERE SUELDO*12 > 1500000;

SELECT NOMBRE FROM CLIENTES WHERE SUBSTR(NOMBRE,1,1) = 'A';

Que no utilizan índice, pero en cambio sí que lo hacen:

SELECT SUELDO FROM EMPLEADOS WHERE SUELDO > 1500000/12;

SELECT NOMBRE FROM CLIENTES WHERE NOMBRE LIKE = 'A%';

En relación con esto, hay que tener en cuenta que las conversiones automáticas que realiza Oracle al comparar
datos de tipos diferentes entran dentro de esta categoría y por tanto inhabilitan el uso del índice. De aquí:

Si hay que hacer conversiones de tipos en la cláusula WHERE, las haremos nosotros explícitamente con las
funciones al efecto como TO_CHAR, TO_DATE, etc., y si es posible, siempre sobre datos fijos, no sobre
columnas.

No utilizar el operador LIKE con un valor cuyo primer carácter sea el comodín '%'; ya que esto obliga a acceder
a toda la tabla. En cambio, Sí que se utilizará índice si la cadena empieza por un carácter fijo. Ejemplo:

(Índice: NOMBRE_CLIENTE)

NOMBRE_CLIENTE LIKE '%AA...' => Acceso a toda la tabla.

NOMBRE_CLIENTE LIKE 'AA%' => Acceso por índice.

Tip: No utilizar LIKE con columnas que no sean de tipo carácter. En este caso, Oracle realiza
implícitamente una conversión de tipo, por tanto, nunca se utilizará índice.

Si en algún caso, queremos obligar al optimizador a realizar un acceso a toda la tabla a pesar de que en la
condición del WHERE se referencie a una columna indexada (Es el caso de tablas muy pequeñas o con un índice
poco restrictivo), podemos utilizar una técnica tan sencilla como:

Página 27 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Para una columna de tipo carácter:

NOMBRE || '' =...

Para una columna de tipo numérico:

TOTAL + 0 = ...

Tip: La optimización basada en costos de Oracle (Default) ya realiza esta operación

Evitar los operadores NOT EQUAL (!=) ya que siempre acceden a toda la tabla al presuponer el analizador que
se va a acceder a la mayoría de los registros. Así:

(Índice: ZONA)

SELECT CLIENTE FROM CLIENTES WHERE ZONA != 5;

no utiliza el índice, pero sí que lo hará:

SELECT CLIENTE FROM CLIENTES WHERE ZONA > 5 AND ZONA < 5;

No hay problema en utilizar las otras condiciones NOT, como por ejemplo:

SELECT CLIENTE FROM CLIENTES WHERE NOT ZONA > 5;

Donde la condición: NOT ZONA > 5 se transformará en ZONA =< 5 y utilizará el índice sobre ZONA de antes.

Para acceder vía índice con la cláusula ORDER BY hay que atender a las mismas consideraciones que las hechas
para WHERE:

La columna del índice no puede estar modificada por una expresión o función.

Las columnas de un índice compuesto han de estar en el mismo orden que en el índice, siendo válidas también
las otras restricciones hechas para el caso de WHERE.

Si la(s) columna(s) de la cláusula ORDER BY no están indexadas o no se puede utilizar el índice, se realiza un
'Sort' de la tabla (o de las filas devueltas por la cláusula WHERE).

Se puede utilizar un acceso por índice con las funciones MAX y MIN en consultas simples (no Joins) si:

No hay cláusula WHERE o GROUP BY

MAX o MIN son la única expresión en la consulta.

Se refieren a una sola columna, sin más operadores.

Página 28 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Por ejemplo:

(Índice IMPORTE)

SELECT MAX(IMPORTE) FROM FACTURAS;

SELECT MAX(IMPORTE)*2 FROM FACTURAS;

Utilizan índice, en cambio, no lo hacen:

SELECT MAX(IMPORTE) FROM FACTURAS WHERE ID_CLI = 15;

SELECT MAX(IMPORTE*2) FROM FACTURAS;

Condiciones ligadas mediante OR. El analizador de Oracle interpreta una cláusula WHERE con n condiciones
unidas con OR como n consultas independientes, cada una con una condición, realizando una concentración al
final. Si queremos tener accesos por índice en este caso, será necesario que cada condición referencie a una
columna indexada.

También se transforma en N consultas independientes una condición con el operador: IN ( Conjunto de valores ),
y por tanto se utilizará un índice si la columna de la condición está indexada.

Evitar siempre que sea posible las funciones de grupo: DISTINCT, GROUP BY.

Nunca utilizan índice y realizan siempre una ordenación (Sort) de la tabla: Las operaciones de Sort son unas de
las que más cargan el servidor, especialmente si tiene que recurrir al tablespace temporal al llenarse la
SORT_AREA de la SGA, ya que entonces hay I/O extra sobre el disco.

Se pueden substituir por una Join aunque ello puede complicar mucho la consulta (hasta hacerla ineficiente) o no
ser posible. En todo caso, siempre hay que incluir una cláusula WHERE previa que restrinja lo más posible las
filas a ordenar y que sí que utilizará un índice para ello si es posible. Por esta razón, es preferible GROUP BY
frente a DISTINCT.

Con GROUP BY utilizar siempre que sea posible WHERE en lugar de HAVING para introducir la condición.
Así la sentencia:

SELECT ZONA, SUM(FACTURACION) FROM CLIENTES WHERE ZONA = 5

GROUP BY ZONA;

utilizará un índice sobre ZONA (si existe), pero la sentencia:

SELECT ZONA, SUM(FACTURACION) FROM CLIENTES GROUP BY ZONA

Página 29 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

HAVING ZONA = 5;

agrupará todos los registros descartando luego los que no tengan ZONA = 5, sin utilizar el índice

No obstante, existen casos en que la presencia de la columna no garantiza el uso de su índice, ya que éstos son
ignorados, como en las siguientes situaciones cuando la columna indexada es:

Evaluada con el uso de los operadores IS NULL o IS NOT NULL.

SELECT nombre,articulo,valor FROM clientes,ventas

WHERE nombre IS NOT NULL;

Modificada por alguna función, excepto por las funciones MAX(columna) o MIN(columna).

SELECT nombre,articulo,valor FROM clientes,ventas

WHERE UPPER(nombre)>' ';

Usada en una comparación con el operador LIKE a un patrón de consulta que comienza con alguno de los signos
especiales (% _).

SELECT nombre,articulo,valor FROM clientes,ventas

WHERE nombre LIKE '%DEPORTE%';

Finalmente debemos aclarar que los registros cuyo valor es NULL para la columna indexada, no forman parte del
índice. Por lo tanto, cuando el índice se activa estos registros no se muestran como resultado de la consulta.

Página 30 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

6.3 Sentencias con Joins.


Una Join es una consulta que combina filas de dos o más tablas. El analizador realizará una Join siempre que
encuentre más de una tabla en la cláusula FROM. Para ello decide que camino de acceso a los datos se ha de seguir
(siendo válidas las consideraciones anteriores sobre el acceso a las tablas por índice) y el algoritmo de Join a emplear.

Para el uso de Joins, aparte de lo dicho antes para índices, hemos de considerar lo siguiente:

En general, es preferible utilizar, si es posible, UNION (mejor UNION ALL si da el resultado buscado, ya que no
realiza 'sort' sobre las tablas, mientras que UNION sí), en lugar de accesos con Join, al menos con tablas de
volúmenes parecidos.

Hay que tener en cuenta la relación entre la tabla conductora y la secundaria: 1 a n (ídem m a n) ó 1 a 1 (ídem n a
1). En el primer caso, accederemos a n filas de la tabla secundaria por cada una de la conductora, mientras que en
el segundo sólo se recuperará una fila de la tabla secundaria por fila de la conductora. Siempre es preferible este
segundo caso, y se ha de intentar obtenerlo mediante funciones de agrupación o eliminación de duplicados, si es
posible obtener el mismo resultado.

Si realizamos una Join entre una vista y una tabla, la vista ha de actuar como conductora.

No es recomendable realizar una Join entre vistas, sobre todo si podemos hacerla sobre las tablas.

Algunas consideraciones sobre el uso de Hints en Joins:

o Si la tabla conductora es mucho más pequeña que la secundaria, es preferible hacer un NL Join.

o Si es la tabla secundaria la que es mucho más pequeña que la conductora, montaremos un Hash Join sobre
la pequeña.

o En principio, si el volumen de las tablas es parecido, también es preferible usar un Hash sobre la tabla
secundaria. Siempre que se use un Hash Join hay que tener en cuenta las columnas seleccionadas, ya que
todas ellas formarán parte de la tabla Hash. Hay que intentar que ésta sea lo más pequeña posible para
reducir el trabajo sobre temporal.

o Con dos tablas pequeñas podemos utilizar un Sort-Merge Join.

Página 31 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

6.4 Sentencias con subconsultas


Una subconsulta es una sentencia SELECT (consulta interna) que proporciona el valor de una condición en el
WHERE de otra consulta (consulta principal). Internamente, el analizador transforma una subconsulta en una Join así
que, en principio, suele ser más efectivo utilizar una Join en lugar de una subconsulta, pero el uso de éstas clarifica
mucho la estructura de la sentencia.

Los operadores MINUS, UNION y INTERSECT no utilizan nunca índices, realizan una ordenación sobre los
datos y optimizan las dos consultas por separado.

Los operadores NOT IN y NOT EXISTS siempre realizan un Full Scan de la tabla de la subconsulta, es más
efectivo utilizar un Outer Join (Producto externo), o bien una subconsulta con MINUS, UNION o INTERSECT.

En general, es mejor utilizar una Join que los operadores IN o EXISTS.

En optimización por reglas, el analizador reescribe la sentencia en un formato más general. Con subconsultas, las
normas generales serían:

o Subconsultas no correlacionadas: Aquellas en que las tablas y condiciones de cada consulta son
independientes. Como, por ejemplo:

SELECT CLIENTE, ID_CLI FROM CLIENTES WHERE ID_CLI IN (SELECT ID_CLI FROM
FACTURAS WHERE MES = 'ENERO')

(Clientes que han facturado en el mes de Enero)

Este tipo de subconsultas se transforman en una Join donde la tabla conductora es la de la consulta interna.
Sólo son convenientes si la consulta interna es muy restrictiva.

o Subconsultas correlacionadas: Aquellas donde la consulta interna incorpora en el WHERE valores de la


tabla de la consulta principal. Ejemplo (reescritura del ejemplo anterior):

ELECT CLIENTE, ID_CLI FROM CLIENTES WHERE ID_CLI EXISTS (SELECT ID_CLI FROM
FACTURAS WHERE FACTURAS.ID_CLI = CLIENTES.ID_CLI AND MES = 'ENERO')

Este tipo de subconsultas de transforman en una Join donde la tabla conductora es la de la consulta principal
que utilizará índices si es posible. Sólo son convenientes si la consulta principal es muy restrictiva.

A pesar de lo dicho, no hay que descartar las subconsultas; en algunos casos, MINUS, UNION o INTERSECT
resultan ser la mejor optimización.

Página 32 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

6.5 Vistas
Una vista es una tabla virtual que está definida por una consulta que consiste en una instrucción SELECT. Esta tabla
virtual está creada con datos de una o más tablas reales y, para los usuarios, una vista parece una tabla real. De hecho,
una vista puede ser tratada del mismo modo que una tabla normal.

En realidad, una vista se almacena simplemente como una instrucción SQL previamente definida. Cuando se accede a
la vista, el DBMS une la instrucción SQL que se ejecuta en ese momento con la consulta que se use para definir la
vista.

Se pueden crear varios tipos de vistas, cada uno de los cuales tienen ventajas en ciertas situaciones. El tipo de vista
que se ha de crear depende completamente de para qué se quiera usar la vista. Se pueden crear vistas de cualquiera de
las siguientes maneras:

Subconjunto de columnas de una tabla

Subconjunto de filas de una tabla

Unión de dos o más tablas

Información de agregación

Ventajas de las vistas

La ventaja de utilizar vistas es que se pueden crear vistas que tienen atributos diferentes sin tener que duplicar los
datos.

Siempre ofrecen los datos actualizados. La instrucción SELECT que define una vista sólo se ejecuta cuando se
accede a la vista, por tanto, todos los cambios de la tabla subyacente se reflejan en la vista.

Puede tener un nivel diferente de seguridad del que posea la tabla subyacente. La consulta que define la vista se
ejecuta con el nivel de seguridad que posea el usuario que crea la vista. De esta manera, se puede crear una vista
que enmascare los datos que no se quieran mostrar a ciertas clases de usuarios.

Página 33 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

7 Optimización ORACLE: Database Tuning


7.1 Generalidades para la optimización de sentencias SQL
El objetivo de la optimización de las sentencias SQL presentes en las aplicaciones es doble; por un lado reducir el
tiempo de respuesta de los usuarios y por otro reducir los recursos utilizados por el sistema para ejecutar las
sentencias.

Es preciso identificar aquellas sentencias SQL que consumen la mayor parte de los recursos del sistema y que
ralentizan los tiempos de respuesta. Oracle nos proporciona la utilidad SQL_TRACE que combinada con la utilidad
TKPROF, nos van a permitir determinar cuales de las sentencias de nuestra aplicación son ineficientes.

Los resultados de salida de las utilidades mencionadas deben ser analizados para tomar las medidas necesarias que
mejoren el rendimiento. Sin embargo, independientemente de los resultados obtenidos podemos tener en cuenta los
siguientes criterios generales.

En las sentencias que se utilice más de una tabla, realizar los equijoins de las mismas con = y con el operador
AND.

Evitar el uso de funciones SQL en la cláusula WHERE. Cualquier expresión que utilice una función provoca que
el optimizador no utilice el índice correspondiente.

Ejemplo: supongamos un índice definido sobre el campo1 de la tabla a

WHERE a.campo1 = b.campo2 è en este caso el optimizador utilizaría el índice al ejecutar la sentencia.

Sin embargo en el caso de utilizar una función WHERE b.campo2 = SUBSTR(a.campo1,1,4) el optimizador no
utilizaría el índice lo que redundaría en una pérdida de eficiencia.

Prestar atención a las conversiones implícitas de datos. Si queremos usar el índice definido sobre la columna
colvchar de tipo VARCHAR2

Colvchar = <num_expr>

y <num_expr> es de tipo NUMBER, la sentencia se trasforma en la siguiente

TO_NUMBER(colvchar) = <num_expr> y al aplicarse la función de conversión el optimizador no


utilizaría el índice.

Simplificar querys complejas con el operador UNION.

Evitar uso de IN y EXITS. En caso de ser necesario su uso, es preferible el IN en aquellos casos en que la
sentencia principal recupere un gran número de filas; en caso contrario, es decir, cuando es la subconsulta la que
presenta una alta cardinalidad es más eficiente el uso de EXITS.

Ejemplo:

La tabla clientes tiene 27.000 filas.

Página 34 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

La tabla pedidos tiene 10.000 filas.

La SELECT selecciona los pedidos realizados por el cliente 1000.

SELECT c.cliente_no, c.cliente_nombre

FROM clientes c

WHERE EXISTS (SELECT 1

FROM pedidos p

WHERE c.cliente_no = p.cliente_no

AND p.cliente_no = 1000)

El plan de ejecución de la sentencia, recupera los 27.000 registros de la tabla clientes y los filtra con la tabla
pedidos, lo que hace que la ejecución sea ineficiente.

Rescribiendo la sentencia con IN:

SELECT c.cliente_no, c.cliente_nombre

FROM clientes c

WHERE c.cliente_no IN (SELECT p.cliente_no

FROM pedidos p

WHERE p.cliente_no = 1000)

El plan de ejecución de la sentencia, recupera los pedidos del cliente 1000 para realizar posteriormente el
join con la tabla clientes, lo que redunda en un mejor rendimiento de la sentencia.

No usar índices de manera generalizada. Los índices suelen mejorar el rendimiento de las sentencias de consulta,
pero ralentizan las operaciones de inserción, borrado y actualización.

Tip: En las cargas masivas de datos deshabilitar constraints y triggers.

Página 35 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

7.2 Tipos de Tablas


7.2.1 Tablas Particionadas
El manejo de tabla de gran tamaño puede producir problemas de rendimiento en nuestra Base de Datos, problema que
puede ser resuelto dividiendo o descomponiendo dichas tablas en pequeñas sub-tablas denominadas particiones.

Una vez definidas las particiones, las sentencias SQL acceden y manipulan los datos de la misma manera que si la
tabla no estuviese particionada. Las tablas particionadas son especialmente útiles en entornos de Datawarehouse
donde la cantidad de datos que se almacenan y analizan es enorme.

Cada una de las particiones en que dividimos una tabla tiene los mismos atributos lógicos que las demás, es decir,
tiene las mismas columnas, los mismos tipos de datos y las mismas restricciones de integridad; sin embargo, cada
partición puede tener diferentes atributos físicos (pctfree, pctused, tablespace,…).

Ventajas de particionar

Se reducen los tiempos de respuesta en las operaciones de manipulación DML puesto que la operación se realiza
sobre una partición en concreto y no sobre toda la tabla.

Se reduce el tiempo de acceso a los datos si estos accesos afectan a una o varias particiones y no a toda la tabla.

Las operaciones de mantenimiento se simplifican puesto que se pueden realizar sobre particiones.

Se puede particionar sin modificar las aplicaciones existentes. Se puede convertir una tabla no particionada en
particionada sin necesidad de modificar ninguna de las sentencias DML que acceden y manipulan los datos de
dicha tabla.

Partition Key

Debemos establecer en base a cual de las columnas o conjuntos de columnas se va a realizar la partición, es lo que se
denomina partition key. A través de la partition key Oracle 9i determina sobre que partición va a realizar las
operaciones DML.

La partition key:

Puede estar formada de 1 a 16 columnas.

ROWID no puede formar parte de la partition key.

No puede contener columnas a NULL.

Una tabla particionada:

Puede ser particionada hasta un máximo de 64.000 particiones.

Página 36 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

No puede contener campos LONG y LONG RAW.

Si puede contener campos LOB y CLOB.

Métodos de particionamiento

Oracle proporciona los siguientes métodos de particionamiento:

Range Partitioning.

List Partitioning.

Hash Partitioning.

Composite Partitioning.

Range Partitioning

Método de particionamiento, que mapea los datos en particiones, definidas sobre rangos del partition key.

Se deberán tener en cuenta las siguientes consideraciones:

Cada partición tiene una cláusula VALUES LESS THAN que indica los límites de la partición.

Todas las particiones excepto la primera tienen un valor inferior del rango definido de manera implícita, por la
partición anterior.

Para la última partición se puede definir un MAXVALUE que indica el valor máximo admitido en dicha
partición.

Ejemplo: Tabla de ventas por cuatrimestres

CREATE TABLE VENTAS_CUATRIMESTRES

(comercial_id NUMBER(4),

comercial_nombre VARCHAR2(40),

region_venta VARCHAR2(6),

importe_venta NUMBER(6),

fecha_venta DATE)

PARTITION BY RANGE (fecha_venta)

Página 37 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

(PARTITION ventas_1cuat VALUES LESS THAN

(TO_DATE (‘01/05/2004’,’DD/MM/YYYY’)),

PARTITION ventas_2cuat VALUES LESS THAN

(TO_DATE (‘01/09/2004’,’DD/MM/YYYY’)),

PARTITION ventas_3cuat VALUES LESS THAN

TO_DATE (‘01/01/20005’,’DD/MM/YYYY’)));

List Partitioning

Método de particionamiento, que mapea los datos en particiones, definidas sobre una lista de valores del partition
key. Las ventajas de este método es que permite organizar los datos del modo adecuado a nuestras necesidades.

Ejemplo: Tabla de ventas particionada agrupando los datos de diferentes regiones.

CREATE TABLE ventas_regiones

(comercial_id NUMBER(4),

comercial_nombre VARCHAR2(40),

region_venta VARCHAR2(6),

importe_venta NUMBER(6),

fecha_venta DATE)

PARTITION BY RANGE (region_venta)

(PARTITION ventas_1region VALUES (‘ASTURIAS’, ‘GALICIA’,

’CANTABRIA’,’MADRID’),

PARTITION ventas_2region VALUES (‘ARAGON’,’CATALUÑA’,

‘VALENCIA’,’BALEARES’),

PARTITION ventas_3region VALUES (‘ANDALUCIA’,’C. LA MANCHA’,

‘MURCIA’));

Página 38 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Hash Partitioning

Método de particionamiento para datos que no admiten una partición por rangos o por lista. Es la mejor opción de
particionamiento en los siguientes casos:

No sabemos a priori el volumen de datos.

Los tamaños de las particiones varían sustancialmente de unas a otras lo que hace difícil equilibrarlas de manera
manual.

Ejemplo: Tabla ventas particionada agrupando los datos por el identificador del comercial.

CREATE TABLE ventas_regiones

(comercial_id NUMBER(4),

comercial_nombre VARCHAR2(40),

region_venta VARCHAR2(6),

importe_venta NUMBER(6),

fecha_venta DATE)

PARTITION BY HASH (comercial_id)

PARTITIONS 4;

Composite Partitioning

Método que combina los métodos anteriores, realizando particiones por rango, y dentro de cada partición sub-
particiones hash o basadas en listas.

Ejemplo: Tabla ventas range-list.

CREATE TABLE ventas_composite_rl

(comercial_id NUMBER(4),

comercial_nombre VARCHAR2(40),

region_venta VARCHAR2(6),

importe_venta NUMBER(6),

Página 39 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

fecha_venta DATE)

PARTITION BY HASH (fecha_venta)

SUBPARTITION BY LIST (region_venta)

SUBPARTITION TEMPLATE (

SUBPARTITION ventas_1region VALUES (‘ASTURIAS’,’GALICIA’,

‘CANTABRIA’,’MADRID’),

SUBPARTITION ventas_2region VALUES (‘ARAGON’,’CATALUÑA’,

‘VALENCIA’,’BALEARES’),

SUBPARTITION ventas_3region VALUES(‘ANDALUCIA’,’MURCIA’,

‘C. LA MANCHA’))

(PARTITION ventas_1cuat VALUES LESS THAN

(TO_DATE (‘01/05/2004’,’DD/MM/YYYY’)),

PARTITION ventas_2cuat VALUES LESS THAN

(TO_DATE (‘01/09/2004’,’DD/MM/YYYY’)),

PARTITION ventas_3cuat VALUES LESS THAN

TO_DATE (‘01/01/20005’,’DD/MM/YYYY’)));

Página 40 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

7.2.2 Tablas Temporales


Además de las tablas estandar, Oracle permite la creación de tablas temporales (temporary tables) que mantienen los
datos únicamente durante la sesión o la transacción en curso. El uso de estas tablas aumneta de manera considerable
el rendimiento ya que los datos permanecen únicamente durante la sesión.

Existen dos tipos de tablas temporales:

GLOBAL TEMPORARY: el contenido de la tabla es accesible desde cualquier sesión.

TEMPORARY: el contenido de la tabla sólo es visible para la sesión en curso.

Ejemplo: Tabla temporal que mantiene las filas (PRESERVE ROWS) una vez que la transacción ha finalizado.

CREATE GLOBAL TEMPORARY TABLE prueba_temp.

(campo1 NUMBER)

ON COMMIT PRESERVE ROWS;

Ejemplo: Tabla temporal que elimina las filas (DELETE ROWS) una vez que la transacción ha finalizado.

CREATE GLOBAL TEMPORARY TABLE prueba_temp.

(campo1 NUMBER)

ON COMMIT DELETE ROWS;

Página 41 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

7.3 Indices, Tipos de índices


Los índices son estructuras de datos asociados a tablas y clúster que incrementan la velocidad de ejecución de las
sentencias SQL. Sin embargo, no siempre los índices producen el efecto deseado, ya que una mala utilización puede
provocar problemas de rendimiento.

Existen varios tipos de índices:

Simples

Compuestos

Basados en funciones (Function-based)

Bit map

Reglas de uso generales:

Los índices aumentan la velocidad de ejecución de las consultas cuando se recupera entre un 10% - 15% de los
datos de la tabla.

Para tablas con gran volumen de datos, los índices ralentizan tanto las consultas como las inserciones,
actualizaciones y borrados.

Las primary keys y las unique key constraints generan implícitamente un índice.

En índices compuestos ordenar las columnas por el orden en que son accedidas con mayor frecuencia.

Las columnas que con frecuencia se usan para ordenar los resultados de las consultas deberán tener asociado un
índice.

Todas las columnas unique deben ser indexadas.

Todas las columnas que formen parte de una foreign key deben ser indexadas para evitar problemas de bloqueos.

Índices basados en funciones

Se pueden crear índices basados en cálculos más o menos complejos entre columnas de las tablas, e incluso aplicando
funciones PL/SQL. La función usada para crear el índice puede ser una expresión aritmética, una expresión que
contenga una función definida en un paquete o una función PL/SQL… La mejora del rendimiento se obtiene cuando
las consultas se realizan en base a dichos cálculos.

Ejemplo. El siguiente ejemplo muestra como definir un índice basado en una función PL/SQL.

Página 42 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

CREATE TABLE empleados

(emp_id NUMBER(2),

emp_nombre VARCHAR2(40));

CREATE INDEX upper_empleados ON empleados (UPPER(emp_nombre));

SELECT emp_nombre

FROM empleados

WHERE UPPER(emp_nombre) = ‘ALBERTO’;

Índices bitmap

Un índice proporciona un puntero a las filas de las tablas que contienen el valor buscado. En un índice normal esto se
consigue almacenando una lista de rowid para cada valor clave que se corresponde con las filas que contienen dicho
valor.

INDICE TABLA DE VENTAS

Id_vendedor ROWID ROWID Id_vendedor Importe_ventas

1000 AFAAAA… AFAAAA 1000 3700

2000 ABAAAA… ABAAAA 2000 850

En un índice bitmap no se almacena una lista de ROWID sino un valor 0 o 1 para cada una de las columnas que
componen el índice. Por lo tanto la eficiencia de estos índices aumenta de manera considerable cuando el número de
condiciones que existen en la cláusula WHERE es elevado.

Página 43 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

7.4 Plan de Ejecución: Interpretación de resultados


Oracle generalmente aplica una optimización basada es costes, que es una estrategia que consiste en la elaboración de
múltiples planes de ejecución de una sentencia, eligiéndose aquella de menor coste de ejecución.

EXPLAIN PLAN muestra el plan de ejecución elegido por el Optimizador de Oracle para ejecutar las sentencias
SELECT, INSERT, UPDATE y DELETE. El plan de ejecución es la secuencia ordenada de operaciones que Oracle
realiza para ejecutar la sentencia correspondiente.

El resultado de EXPLAIN PLAN es un árbol que muestra la siguiente información:

Las tablas referenciadas en la sentencia SQL.

Los métodos de acceso empleados para cada una de las tablas.

Los métodos de unión (join) de las tablas.

Las operaciones realizadas sobre los datos: filtros, ordenaciones, acumulaciones.

EXPLAIN PLAN utiliza la tabla PLAN_TABLE para almacenar los resultados del plan de ejecución. Para crear
dicha tabla en nuestro esquema será necesario ejecutar el script UTLXPLAN.SQL almacenado por lo general en el
path $ORACLE_HOME/rdbms/admin..

Ejecución de EXPLAIN PLAN

A cada una de las sentencias analizadas le asignamos un identificador diferente, para poder consultar el plan de
ejecución de cada una de ellas de manera individual.

EXPLAIN PLAN

SET STATEMENT_ID = <identificador_sentencia>

FOR <sentencia SQL>

Revisión de resultados de EXPLAIN PLAN

Los campos de la tabla PLAN_TABLE más significativos son los siguientes:

Columna Descripción

STATEMENT_ID Valor del identificador especificado en EXPLAIN PLAN

TIMESTAMP Fecha y hora de ejecución

OPERATION Operación ejecutada, contiene los siguientes valores:

SELECT STATEMENTINSERT STATEMENTUPDATE STATEMENTDELETE STATEMENT

Página 44 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

OPTIONS Descripción de la operación

OBJECT_NAME Nombre de la tabla analizada

BYTES Número de bytes accedidos en la ejecución de la sentencia

(Optimizador Basado en Costes)

COST Coste estimado de la sentencia (Optimizador Basado en Costes)

CARDINALITY Número de filas accedidas en la ejecución de la sentencia (Optimizador Basado en Costes)

Los valores más usuales de OPERATION y OPTIONS son los siguientes:

OPERATION OPTION Descripción

INDEX RANGE SCAN Devuelve uno o más ROWID de un índice

MERGE JOIN Operación que acepta dos conjuntos de filas, ordenado cada uno por un valor
específico; combina las filas de uno con las del otro y devuelve el resultado.

NESTED LOOPS Operación sobre dos conjuntos de registros. Compara cada fila de un conjunto con la
del otro, devolviendo las filas que cumplen la condición.

TABLE ACCESS FULL Recupera todos los registros de la tabla

BY INDEX ROWID Recupera los registros por el índice en tablas no particionadas

BY GLOBAL INDEX ROWID Recupera los registros por el índice global en tablas particionadas

BY LOCAL INDEX ROWID Recupera los registros por el índice local en tablas particionadas.

7.5 Utilidades de información estadística sobre la ejecución de sentencias


7.5.1 SQL_Trace
SQL_TRACE proporciona información estadística sobre la ejecución de sentencias SQL. Genera para cada una de las
sentencias los siguientes valores:

Compilaciones (parse), ejecuciones, y lecturas realizadas

Tiempos de proceso de CPU

Número de lecturas lógicas y físicas realizadas

Número de filas procesadas

Página 45 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Fallos producidos en la cache

Esta información es recogida en un fichero con extension .trc. Dicho fichero se almacena en el path indicado por el
parámetro USER_DUMP_DEST. El fichero generado con la traza no es editable por lo que esta utilidad debe ser
combinada con TKPROF.

Podemos activar la traza con SQL_TRACE para una sesión determinada de la siguiente manera:

ALTER SESSION SET SQL_TRACE = TRUE;

Y se desactivaría:

ALTER SESSION SET SQL_TRACE = FALSE;

También puede ser activada desde un proceso PL/SQL del siguiente modo:

BEGIN

DBMS_SESSION.SET_SQL_TRACE (TRUE);

<plsql_procedure_call>;

DBMS_SESSION.SET_SQL_TRACE(FALSE);

END;

En el caso de querer trazar una sesión determinada de un usuario determinado, es preciso obtener previamente el
valor de los campos SID y SERIAL# de la vista del sistema V$SESSION. Se activaría la traza ejecutando la
sentencia:

EXECUTE DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(sid,serial#,TRUE);

Y se desactivaría:

EXECUTE DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(sid,serial#,FALSE);

7.5.2 TKPROF
El fichero con la traza obtenido con SQL_TRACE no es editable. Para poder analizar su contenido es preciso ejecutar
la utilidad TKPROF. Esta utilidad se encuentra normalmente en el path $ORACLE_HOME/BIN y su nombre varía
según las versiones de Oracle (normalmente tkprof.exe).

Para poder ejecutar TKPROF es requisito previo que el parámetro TIMED_STATICS tenga valor TRUE.

Sintaxis

TKPROF tiene como parámetros principales de ejecución los siguientes

Página 46 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

TKPROF <fichero_traza><fichero_salida>

Donde <fichero_traza> es el fichero generado por SQL_TRACE y fichero_salida> el fichero formateado por
TKPROF y a partir del cual se pueden analizar los resultados de la traza.

7.6 Estadísticas
Como administradores de base de datos, podemos generar estadísticas que cuantifiquen la distribución de los datos y
los modos de almacenamiento de las tablas, índices, vistas, particiones, … El optimizador basado en costes (CBO-
Cost Based Optimizer) utiliza esta información para estimar cual es el plan óptimo de ejecución de las sentencias
SQL.

Las estadísticas se almacenan en el diccionario de datos y pueden ser exportadas de una base de datos a otra, de
manera que se pueden simular las condiciones de ejecución de un entorno de desarrollo en uno de producción y
viceversa.

Es conveniente generar estadísticas de manera periódica para un rendimiento óptimo de la base de datos. En
particular deben generarse cuando:

Será necesario para optimizar tener en cuenta los siguientes puntos:

Después de cargar gran cantidad de datos.

Después de cambiar la estructura de los objetos que componen la base de datos.

Generación de estadísticas

El optimizador basado en costes (CBO) utiliza las estadísticas para determinar los métodos de acceso más efectivos.
Por tanto, si el tamaño y la distribución de los datos en las tablas cambia frecuentemente, el generar las estadísticas
regularmente asegura que estas representen con precisión el estado de los datos.

El paquete DBMS_STATS contiene los procedimientos para la generación de estadísticas:

Procedimiento Descripción

GATHER_INDEX_STATS Estadísticas de índices (bitmap)

GATHER_TABLE_STATS Estadísticas de tablas, columnas e índices estáticos

GATHER_SCHEMA_STATS Estadísticas para todos los objetos del esquema

GATHER_DATABASE_STATS Estadísticas para todos los objetos de la BD

GATHER_SYSTEM_STATS Estadísticas del sistema (CPU, I/O)

Página 47 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

8 Diccionario de datos ORACLE


Principalmente se usa de tres maneras:

Oracle accesa el diccionario de datos para hallar la información acerca de los usuarios, esquemas y estructuras
almacenadas.

Oracle modifica el diccionario de datos cada vez que una instrucción DDL es usada.

Cualquier usuario puede usar el diccionario de datos

Hay tres grupos de vistas que contienen información similar y que se distinguen por su prefijo:

Prefijo Descripción

USER_ Vistas con información del esquema del usuario en sesión

Estas vistas presentan al usuario una perspectiva global de la base de datos. Le da al usuario
ALL_
información sobre todos los objetos en la base de datos a los que tiene acceso.

DBA_ Vistas con la información de lo existe en todos los esquemas

Algunas de las principales vistas del diccionario de datos Oracle:

Significado Dba user all

Información sobre todos los objetos:


tablas, vistas, funciones, procs, dba_objects user_objects all_objects
índices, triggers, etc.

Código de funciones y
user_source all_source
procedimientos

Usuarios dba_users user_users all_users

Roles dba_roles

Roles asignados a roles o usuarios Dba_role_privs user_role_privs

Página 48 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Privilegios asignados a roles o


Dba_sys_privs
usuarios

Permisos sobre tablas asignados a


Dba_tab_privs
roles o usuarios

Perfiles y sus límites de recursos


Dba_profiles
asociados

Límites de recursos en cuanto a


user_password_limits
restricciones en claves

Tablespaces Dba_tablespaces user_tablespaces

Secuencias Dba_sequences user_sequences all_sequences

Tablas, vistas, sinónimos y secuencias Dba_catalog user_catalog all_catalog

Tablas Dba_tables user_tables all_tables

Campos de tablas Dba_cons_columns user_cons_columns all_cons_columns

Columnas de las tablas all_cons_columns user_tab_columns all_tab_columns

Vistas Dba_views user_views all_views

Sinónimos Dba_synonyms user_synonyms all_synonyms

Restricciones de clave primaria,


externa, not null, integridad Dba_constraints user_constraints all_constraints
referencial

Índices Dba_indexes user_indexes all_indexes

Columnas de los índices Dba_ind_columns user_ind_columns all_ind_columns

Página 49 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Estas son sólo algunas de las tablas y vistas. Se puede obtener un listado de todas con

select OBJECT_NAME from ALL_OBJECTS;

pero la lista es muy larga, y probablemente sea necesario filtrarla, por ejemplo:

select OBJECT_NAME, OBJECT_TYPE from ALL_OBJECTS where OBJECT_NAME like '%ROLE%';

Para seleccionar sólo un cierto número de registros:

SELECT * FROM EMP WHERE ROWNUM <= 10;

Página 50 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

9 Diccionario de datos SQL Server

Algunas de las principales vistas del diccionario SQL Server:

Contenido INFORMATION_ESCHEMA.

Claves definidas en la Base de Datos CHECK_CONSTRAINTS

Tablas y Vistas de la Base de Datos TABLES

Permisos sobre tablas asignados al usuario


TABLES_PRIVILEGES
actual

Columnas de las Tablas COLUMNS

Permisos sobre las columnas asignados al


COLUMNS_PRIVILEGES
usuario actual

Columnas utilizadas en una Vista VIEW_COLUMN_USAGE

Tablas utilizadas en una vista VIEW_TABLE_USAGE

Vistas VIEWS

Columnas clave definidas de las tablas CONSTRAINT_COLUMN_USAGE

Claves Foráneas REFERENTIAL_CONSTRAINTS

Página 51 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc
Optimización de consultas y SQL avanzado

Tables

Column name Data type Description


TABLE_CATALOG nvarchar(128) Table qualifier.
TABLE_SCHEMA nvarchar(128) Table owner.
TABLE_NAME Sysname Table name.
TABLE_TYPE varchar(10) Type of table. VIEW or BASE TABLE.

Table Constraints

CONSTRAINT_CATALOG nvarchar(128) Constraint qualifier.


CONSTRAINT_SCHEMA nvarchar(128) Constraint owner.
CONSTRAINT_NAME Sysname Constraint name.
TABLE_CATALOG nvarchar(128) Table qualifier.
TABLE_SCHEMA nvarchar(128) Table owner.
TABLE_NAME Sysname Table name.
CONSTRAINT_TYPE varchar(11) Type of constraint. CHECK,
UNIQUE, PRIMARY KEY, or FOREIGN
KEY.
IS_DEFERRABLE varchar(2) Specifies whether constraint
checking is deferrable. Always
returns NO.

Página 52 de 52 © 2005 BearingPoint Global Technology Services


Curso Sql Avanzado.doc

You might also like