metodos de optimizacion de consultas para el lenguaje ... - Blearning
metodos de optimizacion de consultas para el lenguaje ... - Blearning
metodos de optimizacion de consultas para el lenguaje ... - Blearning
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
UNIVERSIDAD DE SANTIAGO DE CHILE<br />
FACULTAD DE CIENCIAS<br />
DEPARTAMENTO DE MATEMATICA Y CIENCIA DE LA COMPUTACION<br />
METODOS DE OPTIMIZACION DE CONSULTAS PARA EL<br />
LENGUAJE SQL.<br />
MARIO CISTERNA NEIRA<br />
SANTIAGO - CHILE<br />
2002
TABLA DE CONTENIDOS<br />
DEFINICIÓN DEL PROBLEMA...........................................................................4<br />
ESTRUCTURA DEL LIBRO..................................................................................6<br />
CAPÍTULO 1. MODELO DE DATOS RELACIONAL.....................................8<br />
1.1. INTRODUCCIÓN. ................................................................................................8<br />
1.2. IMPLEMENTACIONES RELACIONALES................................................................9<br />
1.3. CONCEPTOS GENERALES. ................................................................................10<br />
CAPÍTULO 2. LENGUAJES DE CONSULTA PARA EL MODELO<br />
RELACIONAL. ..........................................................................16<br />
2.1. INTRODUCCIÓN. ..............................................................................................16<br />
2.2. ALGEBRA RELACIONAL. ..................................................................................17<br />
2.3. CÁLCULO RELACIONAL DE TUPLAS. ................................................................23<br />
2.4. SQL COMO LENGUAJE DE CONSULTAS RELACIONALES. ..................................27<br />
CAPÍTULO 3. SISTEMAS DE GESTIÓN DE BASES DE DATOS<br />
RELACIONALES. .....................................................................31<br />
3.1. INTRODUCCIÓN. ..............................................................................................31<br />
3.2. TRANSACCIONES, CONCURRENCIA Y RECUPERACIÓN......................................33<br />
3.3. TIPOS DE SGBD..............................................................................................40<br />
CAPÍTULO 4. INTRODUCCIÓN AL PROCESAMIENTO DE<br />
CONSULTAS, EL ENFOQUE DE SYSTEM R....................48<br />
4.1. INTRODUCCIÓN. ..............................................................................................48<br />
4.2. EL OPTIMIZADOR DE SYSTEM R. .....................................................................51<br />
CAPÍTULO 5. OPTIMIZACIÓN DE CONSULTAS, FUNDAMENTO<br />
TEÓRICO. ..................................................................................69<br />
5.1. INTRODUCCIÓN. ..............................................................................................69<br />
5.2. INFORMACIÓN DEL CATÁLOGO........................................................................70<br />
5.3. MEDIDAS DE COSTO. .......................................................................................72<br />
5.4. EVALUACIÓN DE EXPRESIONES. ......................................................................95<br />
5.5. ORDENES DE JOIN. ........................................................................................107<br />
5.6. ELECCIÓN DE LOS PLANES DE EVALUACIÓN. .................................................123<br />
CAPÍTULO 6. EL OPTIMIZADOR DE CONSULTAS DE SYBASE<br />
ADAPTIVE SERVER ENTERPRISE, UN EJEMPLO<br />
PRÁCTICO...............................................................................128<br />
6.1. INTRODUCCIÓN. ............................................................................................128<br />
6.2. ANÁLISIS DE LA CONSULTA. .........................................................................129<br />
1
6.3. SELECCIÓN DE ÍNDICES. ................................................................................135<br />
6.4. SELECCIÓN DE LOS ORDENES DE JOIN............................................................137<br />
6.5. USO DE TABLAS TEMPORALES.......................................................................147<br />
6.6. SELECCIÓN DEL PLAN....................................................................................148<br />
6.7. RESUMEN......................................................................................................152<br />
RESUMEN Y CONCLUSIONES........................................................................154<br />
RESUMEN.............................................................................................................154<br />
CONCLUSIONES....................................................................................................157<br />
BIBLIOGRAFÍA...................................................................................................160<br />
APÉNDICES. 162<br />
A. SINTAXIS DE SQL..................................................................162<br />
A.1. DEFINICIONES DE DATOS EN SQL.................................................................162<br />
A.2. MANIPULACIÓN DE DATOS EN SQL..............................................................167<br />
B. INDICES B+..............................................................................178<br />
C. MÉTODOS DE ALMACENAMIENTO DE DATOS...........181<br />
C.1. DISCOS MAGNÉTICOS...................................................................................182<br />
2
TABLA DE TABLAS<br />
TABLA 2-1 - OPERADORES DEL ALGEBRA RELACIONAL ........................................................17<br />
TABLA 4-1 - FACTORES DE SELECCIÓN PARA CAMINOS DE ACCESO A RELACIONES SIMPLES.58<br />
TABLA 4-2 - FÓRMULAS DE COSTO PARA CAMINOS DE ACCESO A RELACIONES SIMPLES........61<br />
TABLA 5-1 - INFORMACIÓN DEL CATÁLOGO PARA RELACIONES SIMPLES. .............................71<br />
TABLA 5-2 - INFORMACIÓN DEL CATÁLOGO PARA ÍNDICES DE RELACIONES..........................72<br />
TABLA 5-3 - REGLAS DE EQUIVALENCIA PARA EXPRESIONES RELACIONALES......................104<br />
TABLA A-1 - TIPOS DE DATOS DE SQL................................................................................164<br />
TABLA DE ALGORITMOS<br />
ALGORITMO 5-1 - JOIN EN BUCLES ANIDADOS.......................................................................83<br />
ALGORITMO 5-2 - JOIN EN BUCLES ANIDADOS POR BLOQUES.................................................84<br />
ALGORITMO 5-3 - JOIN POR MEZCLA. ....................................................................................86<br />
ALGORITMO 5-4 - JOIN POR ASOCIACIÓN...............................................................................89<br />
ALGORITMO 5-5 - JOIN ENCAUZADO......................................................................................99<br />
TABLA DE FIGURAS<br />
FIGURA 2-1 - ESQUEMA DE RELACIONES DE EJEMPLO...........................................................18<br />
FIGURA 4-1 - PASOS EN EL PROCESAMIENTO DE UNA CONSULTA SQL...................................50<br />
FIGURA 5-1 - COMPORTAMIENTO DEL ALGORITMO DE SIMULACIÓN DE COCCIÓN ..............116<br />
FIGURA 5-2 - EJEMPLO DEL PRINCIPIO DE SELECCIÓN PARA EL ALGORITMO GENÉTICO PARA LA<br />
OPTIMIZACIÓN DE ORDENES DE JOIN ............................................................................120<br />
FIGURA 5-3 - EJEMPLO DEL PRINCIPIO DE COMBINACIÓN PARA EL ALGORITMO GENÉTICO<br />
PARA LA OPTIMIZACIÓN DE ORDENES DE JOIN..............................................................121<br />
FIGURA 5-4 - UN PLAN DE EVALUACIÓN DE EJEMPLO ..........................................................123<br />
3
Definición <strong>de</strong>l problema.<br />
En Bases <strong>de</strong> datos r<strong>el</strong>acionales <strong>el</strong> <strong>lenguaje</strong> <strong>de</strong> <strong>consultas</strong> SQL es lo más<br />
utilizado por <strong>el</strong> común <strong>de</strong> los programadores y <strong>de</strong>sarrolladores <strong>para</strong> obtener<br />
información <strong>de</strong>s<strong>de</strong> la Base <strong>de</strong> datos. La complejidad que pue<strong>de</strong>n alcanzar algunas<br />
<strong>consultas</strong> pue<strong>de</strong> ser tal, que <strong>el</strong> diseño <strong>de</strong> una consulta pue<strong>de</strong> tomar un tiempo<br />
consi<strong>de</strong>rable, obteniendo no siempre una respuesta optima.<br />
Dada una consulta, generalmente existen varias maneras <strong>de</strong> calcular la<br />
respuesta. En SQL una consulta pue<strong>de</strong> expresarse <strong>de</strong> distintas maneras, todas<br />
<strong>el</strong>las diferentes, como lo expresa C. Date en [Date98], cada una <strong>de</strong> las formas<br />
sugiere una estrategia <strong>para</strong> encontrar la respuesta y por lo tanto algunas pue<strong>de</strong>n<br />
ser más optimas que otras.<br />
El problema que se plantea entonces es, <strong>el</strong> encontrar la manera más<br />
apropiada <strong>de</strong> resolver la consulta, sin que, <strong>el</strong> proceso <strong>de</strong> <strong>de</strong>terminar este resultado<br />
exceda un tiempo razonable y un gasto <strong>de</strong> recursos adicional.<br />
Como respuesta a este problema, nace <strong>el</strong> concepto <strong>de</strong> optimización <strong>de</strong><br />
<strong>consultas</strong>. El objetivo principal <strong>de</strong> este proceso es, encontrar o bien la mejor<br />
alternativa <strong>para</strong> solucionar la consulta, o <strong>de</strong> lo contrario, la alternativa que mejor<br />
cumpla las características <strong>de</strong> eficiencia, entre las estudiadas, cuando no sea<br />
posible estudiarlas todas.<br />
Este proceso tiene que ser lo bastante rápido como <strong>para</strong> que sea<br />
conveniente <strong>para</strong> <strong>el</strong> motor efectuar este cálculo sin afectar <strong>el</strong> rendimiento en la<br />
construcción <strong>de</strong>l resultado <strong>de</strong> la consulta.<br />
4
Uno <strong>de</strong> los primeros estudios r<strong>el</strong>ativo a optimización <strong>de</strong> <strong>consultas</strong> <strong>para</strong> SQL<br />
se hizo sobre <strong>el</strong> prototipo <strong>de</strong> un motor <strong>de</strong> base <strong>de</strong> datos r<strong>el</strong>acional <strong>de</strong>sarrollado por<br />
IBM llamado “system R”, en los laboratorios <strong>de</strong> San José (California) a mediados<br />
<strong>de</strong> la década <strong>de</strong> 1970. Este estudio proporcionaría las bases <strong>para</strong> la construcción<br />
<strong>de</strong> la mayoría <strong>de</strong> los optimizadores <strong>para</strong> motores <strong>de</strong> base <strong>de</strong> datos r<strong>el</strong>acionales <strong>de</strong><br />
or<strong>de</strong>n comercial en la actualidad.<br />
Entre otras cosas, este estudio propone la <strong>de</strong>scomposición <strong>de</strong>l<br />
procesamiento <strong>de</strong> una consulta SQL en 4 fases: <strong>el</strong> análisis sintáctico (parsing), la<br />
optimización, la generación <strong>de</strong> código y la ejecución <strong>de</strong> la consulta.<br />
Se entien<strong>de</strong> entonces como proceso <strong>de</strong> optimización <strong>de</strong> <strong>consultas</strong> al<br />
conjunto <strong>de</strong> técnicas, algoritmos y reglas que le permiten, al motor <strong>de</strong> base <strong>de</strong><br />
datos, <strong>el</strong>egir una alternativa entre varias con la cual pueda rescatar los datos <strong>de</strong> la<br />
manera más optima.<br />
El objetivo principal <strong>de</strong> este trabajo es Investigar este proceso y <strong>de</strong>v<strong>el</strong>arlo,<br />
con la finalidad <strong>de</strong> que <strong>de</strong>je <strong>de</strong> ser algo <strong>de</strong>sconocido <strong>para</strong> quienes interactúan con<br />
Sistemas <strong>de</strong> Gestión <strong>de</strong> bases <strong>de</strong> datos r<strong>el</strong>acionales.<br />
La i<strong>de</strong>a <strong>de</strong> este trabajo es que le sirva <strong>de</strong> apoyo tanto al diseñador <strong>de</strong> base<br />
<strong>de</strong> datos r<strong>el</strong>acionales, como a los <strong>de</strong>sarrolladores que ejecutan <strong>consultas</strong>,<br />
quienes, al enten<strong>de</strong>r mas <strong>de</strong> cerca <strong>el</strong> proceso <strong>de</strong> optimización <strong>de</strong> <strong>consultas</strong><br />
puedan evitar los errores más comunes, que a la larga llevan muchas veces al<br />
fracaso en la construcción e implementación <strong>de</strong> sistemas <strong>de</strong> Información sobre<br />
bases <strong>de</strong> datos r<strong>el</strong>acionales.<br />
5
Estructura <strong>de</strong>l libro.<br />
El Capítulo 1 introduce <strong>el</strong> mo<strong>de</strong>lo r<strong>el</strong>acional <strong>de</strong> datos, <strong>el</strong> cual es la base<br />
<strong>para</strong> <strong>el</strong> <strong>de</strong>sarrollo <strong>de</strong> este trabajo, se presentará un marco <strong>de</strong> trabajo teórico sobre<br />
<strong>el</strong> cual <strong>de</strong>sarrollar <strong>el</strong> problema.<br />
El Capítulo 2 trata sobre los distintos <strong>lenguaje</strong>s <strong>para</strong> recuperación <strong>de</strong> datos<br />
que existen <strong>para</strong> <strong>el</strong> mo<strong>de</strong>lo r<strong>el</strong>acional, otorgando un énfasis especial sobre <strong>el</strong><br />
álgebra r<strong>el</strong>acional y <strong>el</strong> cálculo r<strong>el</strong>acional <strong>de</strong> tuplas, fundamentales <strong>para</strong> la<br />
presentación <strong>de</strong> SQL como <strong>lenguaje</strong> <strong>de</strong> <strong>consultas</strong>.<br />
El procesamiento <strong>de</strong> una consulta SQL <strong>de</strong>pen<strong>de</strong>rá en gran medida <strong>de</strong> la<br />
implemetación r<strong>el</strong>acional en la cual se ejecute, por lo tanto, <strong>el</strong> Capítulo 3 presenta<br />
la conceptualización sobre Sistemas <strong>de</strong> Gestión <strong>de</strong> base <strong>de</strong> datos r<strong>el</strong>acionales<br />
(SGBD), a modo <strong>de</strong> explicación <strong>de</strong> cómo se logran implementaciones r<strong>el</strong>acionales<br />
<strong>de</strong>l mo<strong>de</strong>lo, en este capítulo se explicarán brevemente conceptos tales como<br />
transacciones, concurrencia y repcuperación <strong>de</strong> datos.<br />
El Capítulo 4 Introduce al tema <strong>de</strong>l procesamiento <strong>de</strong> <strong>consultas</strong>, <strong>para</strong> tales<br />
efectos se presenta <strong>el</strong> estudio <strong>de</strong>l optimizador <strong>de</strong> <strong>consultas</strong> <strong>de</strong> System R. Este<br />
SGBD se consi<strong>de</strong>ra una <strong>de</strong> las primeras implementaciones r<strong>el</strong>acionales y motivo<br />
<strong>de</strong> investigación tanto como fundamento y guia <strong>para</strong> la construcción <strong>de</strong> la mayoría<br />
<strong>de</strong> los optimizadores r<strong>el</strong>acionales comerciales actuales. El estudio <strong>de</strong> este caso<br />
introduce conceptos como medidas <strong>de</strong> costo, caminos <strong>de</strong> acceso y utilización <strong>de</strong><br />
heurísticas <strong>de</strong>ntro <strong>de</strong> un optimizador.<br />
El Capítulo 5 <strong>de</strong>sarrolla <strong>el</strong> fundamento teórico <strong>de</strong>l libro, estudia en profundidad <strong>el</strong><br />
proceso <strong>de</strong> optimización <strong>de</strong> <strong>consultas</strong> SQL. Este capítulo explica como los<br />
optimizadores <strong>de</strong>terminan sus medidas <strong>de</strong> costo y en que información se basan<br />
6
<strong>para</strong> estos cálculos; como se produce la evaluación <strong>de</strong> expresiones y como<br />
<strong>de</strong>terminar los or<strong>de</strong>nes <strong>de</strong> Join.<br />
Dado que este trabajo no tiene asociado un <strong>de</strong>sarrollo práctico <strong>de</strong>l tema, <strong>el</strong><br />
Capítulo 6 presenta un ejemplo <strong>de</strong> cómo trabaja en la práctica un optimizador <strong>de</strong><br />
<strong>consultas</strong> <strong>para</strong> un SGBD comercial, <strong>para</strong> tales efectos se presenta <strong>el</strong> caso <strong>de</strong><br />
Sybase Adaptive Server Enterprise (ASE). Este capítulo llevará al lector a<br />
enten<strong>de</strong>r que existe una correspon<strong>de</strong>ncia entre lo presentado en <strong>el</strong> Capítulo 4, lo<br />
explicado en <strong>el</strong> Capítulo 5, y como se logra esto en la práctica.<br />
7
Capítulo 1. Mo<strong>de</strong>lo <strong>de</strong> Datos R<strong>el</strong>acional<br />
1.1. Introducción.<br />
El objetivo <strong>de</strong> todo mo<strong>de</strong>lo <strong>de</strong> datos es proveer conceptos y estructuras <strong>de</strong><br />
datos capaces <strong>de</strong> interpretar los aspectos r<strong>el</strong>evantes que existen en una<br />
<strong>de</strong>terminada parc<strong>el</strong>a <strong>de</strong>l mundo real. Esto se logra mediante un conjunto bien<br />
<strong>de</strong>finido <strong>de</strong> estructuras, operadores y restricciones que actúan sobre dichas<br />
estructuras.<br />
El Mo<strong>de</strong>lo R<strong>el</strong>acional correspon<strong>de</strong> a un enfoque científico y tecnológico que<br />
surgió entre la década <strong>de</strong> 1960 y la década <strong>de</strong> 1970. Su estrategia <strong>de</strong> abstracción<br />
se basa en hacer una representación tabular <strong>de</strong> los objetos y sus asociaciones<br />
entre <strong>el</strong>los. Sin embargo, este enfoque tabular que se sustenta en la teoría <strong>de</strong> las<br />
r<strong>el</strong>aciones matemáticas no permite diferenciar entre los tipos <strong>de</strong> entidad y los tipos<br />
<strong>de</strong> r<strong>el</strong>ación, lo que constituye una pérdida semántica significativa con respecto a<br />
su antecesor, <strong>el</strong> mo<strong>de</strong>lo <strong>de</strong> Entidad-R<strong>el</strong>ación.<br />
Por otra parte, la representación tabular <strong>de</strong> la información y los mecanismos<br />
utilizados <strong>para</strong> establecer vínculos entre las tablas que se representan <strong>de</strong> objetos<br />
r<strong>el</strong>acionados han contribuido enormemente a su masificación, a tal punto que en la<br />
actualidad, <strong>el</strong> Mo<strong>de</strong>lo R<strong>el</strong>acional es un estándar <strong>de</strong> hecho en los que se<br />
construyen los SGBD 1 comerciales.<br />
Es importante notar que <strong>el</strong> mo<strong>de</strong>lo r<strong>el</strong>acional es un mo<strong>de</strong>lo basado en <strong>el</strong><br />
pap<strong>el</strong> y que no todas sus características son implementadas en los SGBD, como a<br />
1 SGBD : Sistemas <strong>de</strong> Gestión <strong>de</strong> Bases <strong>de</strong> datos.<br />
8
su vez muchas implementaciones tienen más características que las que<br />
contempla <strong>el</strong> mo<strong>de</strong>lo.<br />
1.2. Implementaciones R<strong>el</strong>acionales.<br />
Una implementación <strong>de</strong>l mo<strong>de</strong>lo r<strong>el</strong>acional <strong>de</strong>be soportar todas las<br />
facilida<strong>de</strong>s prescritas por <strong>el</strong> mo<strong>de</strong>lo, sin embargo existen algunas características a<br />
las cuales no hace referencia <strong>el</strong> mo<strong>de</strong>lo <strong>de</strong> datos r<strong>el</strong>acional, <strong>de</strong>ntro <strong>de</strong> estas se<br />
incluyen operaciones aritméticas, funciones agregadas, actualizaciones explícitas,<br />
modificaciones, <strong>el</strong>iminaciones, etc. Para esto <strong>el</strong> Mo<strong>de</strong>lo r<strong>el</strong>acional incluye un<br />
núcleo <strong>de</strong> funciones que <strong>de</strong>ben ser incorporadas en un SGBD.<br />
Sin embargo existe una distinción entre las implementaciones consi<strong>de</strong>radas<br />
r<strong>el</strong>acionales y los que no lo son en su totalidad (Pseudo-R<strong>el</strong>acionales). Estas<br />
últimas se pue<strong>de</strong>n clasificar como sigue:<br />
• Tabular : Un SGBD Tabular es una implementación <strong>de</strong> una Base <strong>de</strong> datos<br />
r<strong>el</strong>acional que soporta las estructuras <strong>de</strong> datos tabulares (tablas), pero no<br />
los operadores <strong>de</strong> niv<strong>el</strong> <strong>de</strong> conjuntos.<br />
• R<strong>el</strong>acional Mínimo: Un SGBD Mínimamente r<strong>el</strong>acional es una<br />
implementación <strong>de</strong> bases <strong>de</strong> datos r<strong>el</strong>acionales que soporta sólo tablas, los<br />
operadores <strong>de</strong> s<strong>el</strong>ección, proyección y <strong>el</strong> operador JOIN (pero no los otros<br />
operadores r<strong>el</strong>acionales).<br />
• R<strong>el</strong>acional Completo: Un SGBD Completamente r<strong>el</strong>acional es una<br />
implementación <strong>de</strong> bases <strong>de</strong> datos r<strong>el</strong>acionales que soporta sólo tablas y<br />
todos los operadores <strong>de</strong>l álgebra r<strong>el</strong>acional.<br />
9
• R<strong>el</strong>acional : Un SGBD R<strong>el</strong>acional es una implementación <strong>de</strong> Bases <strong>de</strong><br />
datos r<strong>el</strong>acionales que soporta todos los aspectos <strong>de</strong>l mo<strong>de</strong>lo r<strong>el</strong>acional<br />
incluidos los dominios y las dos reglas generales <strong>de</strong> Integridad (que se<br />
explicarán más a<strong>de</strong>lante, en <strong>el</strong> punto 1.3.12).<br />
1.3. Conceptos generales.<br />
1.3.1. Datos Atómicos<br />
Todos los valores <strong>de</strong> datos en <strong>el</strong> mo<strong>de</strong>lo r<strong>el</strong>acional son atómicos. Esto<br />
implica que cada posición <strong>de</strong> fila-columna en cada tabla siempre tiene sólo un<br />
dato, y nunca un conjunto <strong>de</strong> valores.<br />
1.3.2. Tuplas<br />
Una tupla <strong>de</strong> una r<strong>el</strong>ación o <strong>de</strong> una tabla correspon<strong>de</strong> a una fila <strong>de</strong> aqu<strong>el</strong>la<br />
tabla. Las tuplas están comúnmente <strong>de</strong>sor<strong>de</strong>nadas puesto que matemáticamente<br />
una r<strong>el</strong>ación se <strong>de</strong>fine como un conjunto y no como una lista. No Existen tuplas<br />
duplicadas en una r<strong>el</strong>ación o tabla dado <strong>el</strong> hecho <strong>de</strong> que una r<strong>el</strong>ación es un<br />
conjunto y los conjuntos por <strong>de</strong>finición no permiten <strong>el</strong>ementos duplicados. Un<br />
corolario importante en este punto es que la llave primaria siempre existe dada la<br />
condición <strong>de</strong> unicidad <strong>de</strong> las tuplas, por lo tanto, como mínimo la combinación <strong>de</strong><br />
todos los atributos <strong>de</strong> una tabla pue<strong>de</strong> servir <strong>para</strong> la conformación <strong>de</strong> la llave<br />
primaria, sin embargo usualmente no es necesario incluir todos los atributos,<br />
comúnmente algunas combinaciones mínimas son suficientes.<br />
1.3.3. Dominios.<br />
Un dominio se <strong>de</strong>fine como un conjunto <strong>de</strong> valores <strong>de</strong>l mismo tipo. Por<br />
ejemplo <strong>el</strong> dominio que correspon<strong>de</strong> a la edad <strong>de</strong> una persona (en años) se pue<strong>de</strong><br />
10
<strong>de</strong>finir como <strong>el</strong> conjunto <strong>de</strong> todos los valores <strong>de</strong> números posibles <strong>de</strong> eda<strong>de</strong>s, por<br />
ejemplo <strong>de</strong>s<strong>de</strong> 0 hasta 120. Siempre y cuando dos atributos tomen sus valores <strong>de</strong>l<br />
mismo dominio estos pue<strong>de</strong>n ser com<strong>para</strong>dos aunque pertenezcan a distintas<br />
tablas. Los dominios son especificados como parte <strong>de</strong> la <strong>de</strong>finición <strong>de</strong> los datos,<br />
estos pue<strong>de</strong>n ser simples o compuestos. Un dominio compuesto se <strong>de</strong>fine como<br />
<strong>el</strong> producto <strong>de</strong> alguna colección <strong>de</strong> dominios simples. Por ejemplo la fecha es<br />
producto <strong>de</strong> <strong>el</strong> día, <strong>el</strong> mes y <strong>el</strong> año, don<strong>de</strong> <strong>el</strong> mes es <strong>el</strong> dominio simple <strong>de</strong> 1 a 12 y<br />
así sucesivamente).<br />
1.3.4. Atributos.<br />
Un atributo <strong>de</strong> una r<strong>el</strong>ación o <strong>de</strong> una tabla correspon<strong>de</strong> a una columna <strong>de</strong> la<br />
tabla. Los atributos están <strong>de</strong>sor<strong>de</strong>nados y se referencian por nombres y no por la<br />
posición que ocupan. Esto significa que no se pue<strong>de</strong>, por ejemplo, hacer<br />
referencia al tercer atributo <strong>de</strong> una r<strong>el</strong>ación. Todos los valores <strong>de</strong> los atributos son<br />
atómicos y una r<strong>el</strong>ación que satisfaga esta condición se llama r<strong>el</strong>ación<br />
normalizada. Un atributo extrae sus valores <strong>de</strong>s<strong>de</strong> un dominio simple.<br />
Formalmente, un atributo es una función que se <strong>de</strong>fine entre un Dominio y<br />
un <strong>de</strong>terminado tipo <strong>de</strong> Entidad <strong>de</strong> la base <strong>de</strong> datos. Dicha función asocia una<br />
ocurrencia <strong>de</strong> Tipo <strong>de</strong> Entidad con un <strong>de</strong>terminado <strong>el</strong>emento <strong>de</strong>l dominio.<br />
1.3.5. Esquema <strong>de</strong> R<strong>el</strong>ación.<br />
Un esquema <strong>de</strong> r<strong>el</strong>ación es <strong>el</strong> conjunto que i<strong>de</strong>ntifica todas las propieda<strong>de</strong>s<br />
(Atributos) <strong>de</strong> un objeto. Se representa por <strong>el</strong> conjunto :<br />
{ A A , A A }<br />
E = ,......<br />
1,<br />
2 3<br />
don<strong>de</strong> , i = 1,...<br />
n correspon<strong>de</strong> a un atributo y n <strong>el</strong> número <strong>de</strong> atributos <strong>de</strong><br />
A i<br />
interés <strong>de</strong>l objeto.<br />
n<br />
11
1.3.6. R<strong>el</strong>ación<br />
Formalmente, una r<strong>el</strong>ación R es un conjunto <strong>de</strong> n-tuplas tal que una n-tupla<br />
cualquiera x es:<br />
{ ( , a)<br />
/ A ∈ E,<br />
a ∈ Dom(<br />
A ), ∀i,<br />
i = 1,.....<br />
n}<br />
Ai i<br />
i<br />
don<strong>de</strong> E es <strong>el</strong> esquema <strong>de</strong> la r<strong>el</strong>ación.<br />
Las propieda<strong>de</strong>s fundamentales <strong>de</strong> una r<strong>el</strong>ación son :<br />
• No hay tuplas repetidas.<br />
• Las tuplas no están or<strong>de</strong>nadas.<br />
• Los atributos no están or<strong>de</strong>nados.<br />
• Todos los valores que toman las propieda<strong>de</strong>s son atómicos.<br />
1.3.7. Grado <strong>de</strong> una r<strong>el</strong>ación<br />
El grado <strong>de</strong> una r<strong>el</strong>ación es <strong>el</strong> numero <strong>de</strong> atributos en la r<strong>el</strong>ación. Una<br />
r<strong>el</strong>ación <strong>de</strong> grado 1 (uno) es llamada unaria, una r<strong>el</strong>ación <strong>de</strong> grado 2 es llamada<br />
binaria, una r<strong>el</strong>ación <strong>de</strong> grado n es llamada <strong>de</strong> “grado n”. Los Grados <strong>de</strong> una<br />
r<strong>el</strong>ación no cambian todo <strong>el</strong> tiempo, pero es posible que se agreguen nuevas<br />
columnas y se creen nuevas r<strong>el</strong>aciones.<br />
12
1.3.8. Cardinalida<strong>de</strong>s <strong>de</strong> una r<strong>el</strong>ación.<br />
La cardinalidad <strong>de</strong> una r<strong>el</strong>ación en un <strong>de</strong>terminado momento está <strong>de</strong>finida<br />
como <strong>el</strong> número <strong>de</strong> tuplas en la r<strong>el</strong>ación. Esta pue<strong>de</strong> cambiar en cualquier<br />
momento.<br />
1.3.9. Compatibilidad <strong>de</strong> dos r<strong>el</strong>aciones.<br />
Sean A y B dos r<strong>el</strong>aciones con esquemas = { A , A ,..... A } y<br />
{ A , A ,..... A }<br />
E2 21 22 2n<br />
si :<br />
E1 11 12 1n<br />
= respectivamente. Se dice que A y B son compatibles si y sólo<br />
1. ∀ P, P ∈E1∃!<br />
P',<br />
P'∈<br />
E2<br />
tal que Dom ( P)<br />
= Dom(<br />
P')<br />
2. ∀ P, P ∈E<br />
2∃!<br />
P',<br />
P'∈<br />
E1<br />
tal que Dom ( P)<br />
= Dom(<br />
P')<br />
En la práctica, esto significa que ambas r<strong>el</strong>aciones <strong>de</strong>ben ser <strong>de</strong>l mismo<br />
grado n y que <strong>el</strong> i-esimo atributo <strong>de</strong> cada r<strong>el</strong>ación se <strong>de</strong>be basar en <strong>el</strong> mismo<br />
dominio.<br />
1.3.10. Llave Primaria / Llave Candidata<br />
La llave primaria <strong>de</strong> una r<strong>el</strong>ación o tabla es <strong>de</strong> hecho un caso especial <strong>de</strong><br />
una construcción más general llamada la llave candidata. Una llave candidata es<br />
un atributo que sirve como i<strong>de</strong>ntificador único <strong>para</strong> una <strong>de</strong>terminada tabla. Una <strong>de</strong><br />
las llaves candidatas es <strong>el</strong>egida <strong>para</strong> ser la llave primaria, las restantes pasarán a<br />
llamarse claves alternativas. De todos modos, comúnmente sólo hay una sola<br />
llave candidata. Las llaves primarias proporcionan un mecanismo <strong>de</strong><br />
direccionamiento único a niv<strong>el</strong> <strong>de</strong> tuplas <strong>para</strong> <strong>el</strong> mo<strong>de</strong>lo r<strong>el</strong>acional. Garantizan un<br />
único camino <strong>para</strong> llegar a una tupla individual y por lo tanto son fundamentales<br />
<strong>para</strong> las operaciones sobre <strong>el</strong> mo<strong>de</strong>lo r<strong>el</strong>acional.<br />
13
Formalmente, una llave se <strong>de</strong>fine como:<br />
Sea ε una r<strong>el</strong>ación con esquema E { A A , A ,...... A }<br />
1,<br />
2 3<br />
n<br />
14<br />
= . Una Llave <strong>de</strong> la<br />
r<strong>el</strong>ación ε es un atributo o un conjunto <strong>de</strong> atributos K { C , C ,..... C }<br />
= que cumple :<br />
• Unicidad: No existen dos tuplas <strong>de</strong> ε tales que <strong>para</strong> <strong>el</strong>las, <strong>el</strong> conjunto<br />
<strong>de</strong> atributos que componen K tienen los mismos valores.<br />
• Minimalidad: Ninguno <strong>de</strong> los atributos que componen K pue<strong>de</strong> ser<br />
<strong>el</strong>iminado sin afectar la unicidad.<br />
1.3.11. Llaves externas<br />
Una Llave externa se <strong>de</strong>fine como un atributo (o combinación <strong>de</strong> atributos)<br />
en una r<strong>el</strong>ación cuyos valores se requieren <strong>para</strong> emparejar a los valores <strong>de</strong> la llave<br />
primaria <strong>de</strong> otra r<strong>el</strong>ación. La llave externa y su correspondiente llave primaria<br />
<strong>de</strong>ben ser <strong>de</strong>finidas en <strong>el</strong> mismo dominio.<br />
Una llave externa no tiene que ser componente <strong>de</strong> la llave primaria <strong>de</strong> la<br />
r<strong>el</strong>ación que la contiene. El emparejamiento entre una llave externa y una llave<br />
primaria representa una referencia entre dos r<strong>el</strong>aciones, <strong>el</strong>las son <strong>el</strong> “pegamento”<br />
que mantiene la base <strong>de</strong> datos unida.<br />
1.3.12. Reglas <strong>de</strong> Integridad.<br />
Existen básicamente 2 reglas <strong>de</strong> integridad asociadas con <strong>el</strong> mo<strong>de</strong>lo<br />
r<strong>el</strong>acional, la Integridad <strong>de</strong> Entidad y la Integridad Referencial. Estas dos reglas<br />
son generales, se aplican a toda base <strong>de</strong> datos r<strong>el</strong>acional y tienen que ver con las<br />
llaves primarias y externas respectivamente. Estas reglas se refieren a los estados<br />
i<br />
j<br />
l
<strong>de</strong> la base <strong>de</strong> datos. Dado que no existe un acuerdo <strong>de</strong> como se <strong>de</strong>ben evitar los<br />
cambios <strong>de</strong> estado en la base <strong>de</strong> datos es que muchos SGBD <strong>de</strong>tienen la<br />
ejecución <strong>de</strong> la tarea en curso cada vez que se incurre en una violación a una <strong>de</strong><br />
estas reglas.<br />
La regla <strong>de</strong> Integridad <strong>de</strong> Entidad norma sobre la imposibilidad <strong>de</strong> que un<br />
atributo que componga la llave primaria <strong>de</strong> una r<strong>el</strong>ación base acepte valores nulos<br />
(NULL) 2 .<br />
La regla <strong>de</strong> integridad referencial <strong>para</strong> <strong>el</strong> mo<strong>de</strong>lo r<strong>el</strong>acional formula que si<br />
una r<strong>el</strong>ación R2 incluye una llave externa FK que empareja a una llave primaria<br />
PK <strong>de</strong> alguna r<strong>el</strong>ación R1, entonces cada valor <strong>de</strong> FK en R2 <strong>de</strong>be:<br />
a) Ser igual al valor <strong>de</strong> PK en alguna tupla <strong>de</strong> R1<br />
o<br />
b) Ser totalmente Nula, esto es, cada atributo en FK <strong>de</strong>be ser nulo.<br />
2 Un Valor nulo en <strong>el</strong> mo<strong>de</strong>lo r<strong>el</strong>acional es un valor especial distinto <strong>de</strong> cero o blanco<br />
(<strong>de</strong>pendiendo <strong>de</strong>l tipo <strong>de</strong> dato) que significa “No aplicable” o “Desconocido”. Para mayor <strong>de</strong>talle,<br />
ver la discusión sobre valores nulos en [McJones97].<br />
15
Capítulo 2. Lenguajes <strong>de</strong> consulta <strong>para</strong> <strong>el</strong> Mo<strong>de</strong>lo<br />
R<strong>el</strong>acional.<br />
2.1. Introducción.<br />
Un <strong>lenguaje</strong> <strong>de</strong> consulta es un <strong>lenguaje</strong> en <strong>el</strong> que <strong>el</strong> usuario solicita<br />
información <strong>de</strong> la base <strong>de</strong> datos, Los <strong>lenguaje</strong>s <strong>de</strong> consulta se pue<strong>de</strong>n clasificar en<br />
procedurales y no procedurales. Los <strong>lenguaje</strong>s procedurales son aqu<strong>el</strong>los en los<br />
cuales <strong>el</strong> usuario instruye al sistema <strong>para</strong> que lleve a cabo una serie <strong>de</strong><br />
operaciones en la base <strong>de</strong> datos con <strong>el</strong> fin <strong>de</strong> calcular <strong>el</strong> resultado <strong>de</strong>seado. En<br />
los <strong>lenguaje</strong>s no procedurales, en cambio, <strong>el</strong> usuario <strong>de</strong>scribe la información<br />
<strong>de</strong>seada sin dar un procedimiento concreto <strong>para</strong> obtener esta información.<br />
Los <strong>lenguaje</strong>s puros <strong>para</strong> la consulta <strong>de</strong> datos son 3. El álgebra r<strong>el</strong>acional,<br />
<strong>el</strong> cual es procedural y los cálculos r<strong>el</strong>acionales tanto <strong>de</strong> tuplas como <strong>de</strong> dominios,<br />
los cuales son <strong>lenguaje</strong>s no procedurales. Estos 3 <strong>lenguaje</strong>s son rígidos y<br />
formales, por lo tanto la mayor parte <strong>de</strong> los sistemas comerciales <strong>de</strong> bases <strong>de</strong><br />
datos r<strong>el</strong>acionales ofrecen <strong>lenguaje</strong>s <strong>de</strong> consulta mixtos, que a<strong>de</strong>más <strong>de</strong> ser ricos<br />
en sintaxis ofrecen adicionalmente sub<strong>lenguaje</strong>s <strong>de</strong> <strong>de</strong>finición <strong>de</strong> datos,<br />
administración <strong>de</strong> seguridad y otras características.<br />
Se estudiarán brevemente dos <strong>de</strong> los tres <strong>lenguaje</strong>s puros <strong>de</strong> <strong>consultas</strong> <strong>de</strong> base<br />
<strong>de</strong> datos, con <strong>el</strong> fin <strong>de</strong> presentar una base teórica <strong>para</strong> introducir SQL. Se excluirá<br />
<strong>el</strong> cálculo r<strong>el</strong>acional <strong>de</strong> dominios dado que es una generalización <strong>de</strong>l cálculo<br />
r<strong>el</strong>acional <strong>de</strong> tuplas y queda fuera <strong>de</strong>l alcance <strong>de</strong> este trabajo. Para un estudio<br />
más acabado <strong>de</strong>l cálculo r<strong>el</strong>acional <strong>de</strong> dominios se recomienda leer<br />
[Silbercshatz93].<br />
16
2.2. Algebra r<strong>el</strong>acional.<br />
El Algebra r<strong>el</strong>acional es un <strong>lenguaje</strong> <strong>de</strong> consulta procedural. Consta <strong>de</strong> un<br />
conjunto <strong>de</strong> operaciones que toman como entrada una o dos r<strong>el</strong>aciones y<br />
producen como resultado una nueva r<strong>el</strong>ación, por lo tanto, es posible anidar y<br />
combinar operadores. Hay ocho operadores en <strong>el</strong> álgebra r<strong>el</strong>acional que<br />
construyen r<strong>el</strong>aciones y manipulan datos, estos son:<br />
1. S<strong>el</strong>ección 2. Proyección 3. Producto<br />
4. Unión 5. Intersección 6. Diferencia<br />
7. JOIN 8. División<br />
Tabla 2-1 - Operadores <strong>de</strong>l Algebra r<strong>el</strong>acional<br />
Las operaciones <strong>de</strong> proyección, producto, unión, diferencia, y s<strong>el</strong>ección son<br />
llamadas primitivas, puesto que las otras tres se pue<strong>de</strong>n <strong>de</strong>finir en términos <strong>de</strong><br />
estas.<br />
Se hace necesario en este punto incluir un mo<strong>de</strong>lo <strong>de</strong> datos <strong>de</strong> ejemplo en<br />
<strong>el</strong> cual trabajar <strong>para</strong> generar ejemplos <strong>de</strong> comandos y operadores. Para este<br />
efecto se incluye un mo<strong>de</strong>lo básico <strong>de</strong> administración <strong>de</strong> RadioTaxis. El Gráfico<br />
que se presenta a continuación representa <strong>el</strong> Mo<strong>de</strong>lo conceptual (Mo<strong>de</strong>lo Lógico)<br />
o Diagrama <strong>de</strong> Entidad-R<strong>el</strong>ación:<br />
17
Vale<br />
Corr<strong>el</strong>ativo<br />
Hora <strong>de</strong>s<strong>de</strong><br />
Hora Hasta<br />
Metraje total<br />
Tarifa Total<br />
Dueño<br />
Rut<br />
Nombre<br />
T<strong>el</strong>éfono<br />
Dirección<br />
Vigencia<br />
posee es <strong>de</strong> un<br />
por genera un<br />
Movil<br />
Patente<br />
Marca<br />
Mo<strong>de</strong>lo<br />
Año<br />
realiza<br />
los hace un<br />
Viaje<br />
Hora Des<strong>de</strong><br />
Hora Hasta<br />
Origen<br />
Destino<br />
Tarifa<br />
Metraje<br />
lo maneja<br />
Figura 2-1 - Esquema <strong>de</strong> R<strong>el</strong>aciones <strong>de</strong> Ejemplo<br />
maneja<br />
Chofer<br />
Rut<br />
Nombre<br />
T<strong>el</strong>éfono<br />
Dirección<br />
Fecha_licencia_<strong>de</strong>s<strong>de</strong><br />
Fecha_licencia_hasta<br />
Vigencia<br />
Conceptual Data Mo<strong>de</strong>l<br />
Project : Control <strong>de</strong> RadioTaxis<br />
Mo<strong>de</strong>l : RadioTax<br />
Author : Mario Cisterna Version 28/12/98<br />
Los Esquemas <strong>de</strong> r<strong>el</strong>aciones que se pue<strong>de</strong>n construir a partir <strong>de</strong> este<br />
mo<strong>de</strong>lo son los siguientes:<br />
Dueño = {rut, nombre, t<strong>el</strong>éfono, dirección, vigencia}<br />
Chofer = {rut, nombre, t<strong>el</strong>éfono, dirección, fecha_licencia_<strong>de</strong>s<strong>de</strong>,<br />
fecha_licencia_hasta, vigencia}<br />
Vale = {corr<strong>el</strong>ativo, hora_<strong>de</strong>s<strong>de</strong>, hora_hasta, metraje_total,<br />
tarifa_total}<br />
Móvil = {patente, rut_dueño, rut_chofer, marca, mo<strong>de</strong>lo, año}<br />
Viaje = {corr<strong>el</strong>ativo_vale, patente_movil, Hora_Des<strong>de</strong>,<br />
hora_hasta, origen, <strong>de</strong>stino, tarifa, metraje}<br />
2.2.1. S<strong>el</strong>ección.<br />
El operador <strong>de</strong> s<strong>el</strong>ección opta por tuplas que satisfagan cierto predicado, se<br />
utiliza la letra griega sigma minúscula (σ) <strong>para</strong> señalar la s<strong>el</strong>ección. El predicado<br />
18
aparece como subíndice <strong>de</strong> σ. La R<strong>el</strong>ación que constituye <strong>el</strong> argumento se da<br />
entre paréntesis <strong>de</strong>spués <strong>de</strong> la σ.<br />
Ejemplos :<br />
2.2.2. Proyección.<br />
' ' ( ) Dueño<br />
σ vigencia = S<br />
σ<br />
patente = 'HL−8483'<br />
( Movil )<br />
La operación <strong>de</strong> proyección permite quitar ciertos atributos <strong>de</strong> la r<strong>el</strong>ación,<br />
esta operación es unaria, copiando su r<strong>el</strong>ación base dada como argumento y<br />
quitando ciertas columnas, La proyección se señala con la letra griega pi<br />
mayúscula (Π). Como subíndice <strong>de</strong> Π se coloca una lista <strong>de</strong> todos los atributos que<br />
se <strong>de</strong>sea aparezcan en <strong>el</strong> resultado. La r<strong>el</strong>ación argumento se escribe <strong>de</strong>spués <strong>de</strong><br />
Π entre paréntesis.<br />
Ejemplos :<br />
2.2.3. Producto.<br />
Π nombre,<br />
direccion ( Dueño)<br />
Π rut,<br />
vigencia ( Chofer )<br />
En álgebra r<strong>el</strong>acional <strong>el</strong> producto <strong>de</strong> dos r<strong>el</strong>aciones A y B es:<br />
A Veces B o A X B<br />
19
Produce <strong>el</strong> conjunto <strong>de</strong> todas las tuplas t tales que t es <strong>el</strong> enca<strong>de</strong>namiento <strong>de</strong> una<br />
tupla a perteneciente a A y <strong>de</strong> una b que pertenece a B. se utiliza <strong>el</strong> símbolo X<br />
<strong>para</strong> representar <strong>el</strong> producto.<br />
Ejemplos:<br />
2.2.4. Unión.<br />
Dueño × Movil<br />
Movil × Chofer<br />
En álgebra r<strong>el</strong>acional la unión <strong>de</strong> dos r<strong>el</strong>aciones compatibles 3 A y B es:<br />
A UNION B o A ∪ B<br />
Produce <strong>el</strong> conjunto <strong>de</strong> todas las tuplas que pertenecen ya sea a A o a B o a<br />
Ambas. Al igual que en teoría <strong>de</strong> conjuntos <strong>el</strong> símbolo ∪ representa aquí la unión<br />
<strong>de</strong> dos r<strong>el</strong>aciones.<br />
Ejemplo :<br />
2.2.5. Intersección.<br />
σ ∪ σ<br />
rut,<br />
vigencia(<br />
Dueño) rut,<br />
vigencia(<br />
Chofer)<br />
Devu<strong>el</strong>ve todos los Dueños y los Choferes.<br />
En álgebra r<strong>el</strong>acional la intersección <strong>de</strong> dos r<strong>el</strong>aciones compatibles A y B<br />
3 R<strong>el</strong>aciones Compatibles : En <strong>el</strong> álgebra r<strong>el</strong>acional la compatibilidad se aplica a las<br />
operaciones <strong>de</strong> Unión, Intersección y Diferencia. Cada operación requiere dos r<strong>el</strong>aciones que<br />
<strong>de</strong>ben ser compatibles, esto significa que <strong>de</strong>ben ser <strong>de</strong>l mismo grado, n, y <strong>el</strong> i-ésimo atributo <strong>de</strong><br />
cada una (i= 1, 2…n) se <strong>de</strong>be basar en <strong>el</strong> mismo dominio.<br />
20
A INTERSECCION B o A ∩ B<br />
Produce <strong>el</strong> conjunto <strong>de</strong> todas las tuplas pertenecientes a A y B. Al igual que en<br />
teoría <strong>de</strong> conjuntos <strong>el</strong> símbolo ∩ representa aquí la intersección entre dos<br />
r<strong>el</strong>aciones.<br />
Ejemplo:<br />
2.2.6. Diferencia<br />
σ ∩ σ<br />
rut,<br />
vigencia(<br />
Dueño) rut,<br />
vigencia(<br />
Chofer)<br />
Devu<strong>el</strong>ve todos los dueños que también son choferes<br />
En álgebra r<strong>el</strong>acional la diferencia entre dos r<strong>el</strong>aciones compatibles A y B<br />
A MENOS B o A – B<br />
Produce <strong>el</strong> conjunto <strong>de</strong> todas las tuplas t que pertenecen a A y no pertenecen a B.<br />
Ejemplo:<br />
2.2.7. Join o Reunión.<br />
σ − σ<br />
rut,<br />
vigencia(<br />
Dueño) rut,<br />
vigencia(<br />
Chofer)<br />
Devu<strong>el</strong>ve todos los dueños que NO son choferes<br />
En álgebra r<strong>el</strong>acional <strong>el</strong> JOIN entre <strong>el</strong> atributo X <strong>de</strong> la r<strong>el</strong>ación A con <strong>el</strong><br />
atributo Y <strong>de</strong> la r<strong>el</strong>ación B produce <strong>el</strong> conjunto <strong>de</strong> todas las tuplas t tal que t es <strong>el</strong><br />
enca<strong>de</strong>namiento <strong>de</strong> una tupla a perteneciente a A y una tupla b perteneciente a B<br />
que cumplen con <strong>el</strong> predicado “A.X comp B.Y es verda<strong>de</strong>ro” (siendo comp un<br />
21
operador r<strong>el</strong>acional y los atributos A.X y B.Y pertenecientes al mismo dominio). Si<br />
<strong>el</strong> operador r<strong>el</strong>acional “comp” es “=” entonces <strong>el</strong> conjunto resultante es un EQUI-<br />
JOIN. Si se quita uno <strong>de</strong> éstos (usando una proyección) entonces <strong>el</strong> resultado es<br />
un JOIN-NATURAL.<br />
Ejemplo :<br />
2.2.8. División<br />
σ<br />
Dueño . rut = Movil . rut _ dueño ( Dueño × Movil )<br />
En álgebra r<strong>el</strong>acional <strong>el</strong> operador <strong>de</strong> división divi<strong>de</strong> la r<strong>el</strong>ación A con grado<br />
m + n por la r<strong>el</strong>ación B entregando como resultado una r<strong>el</strong>ación con grado m. El<br />
atributo m + i <strong>de</strong> A y <strong>el</strong> atributo i <strong>de</strong> B <strong>de</strong>ben estar <strong>de</strong>finidos <strong>de</strong>ntro <strong>de</strong>l mismo<br />
dominio. Así <strong>el</strong> resultado <strong>de</strong><br />
A DIVIDIDO POR B o A / B<br />
produce la r<strong>el</strong>ación C con un sólo atributo X, tal que cada valor <strong>de</strong> x <strong>de</strong> C.X<br />
aparece como un valor <strong>de</strong> A.X, y <strong>el</strong> par <strong>de</strong> valores (x, y) aparece en A <strong>para</strong> todos<br />
los valores y que aparecen en B.<br />
Ejemplo:<br />
Π ) / Π ( σ<br />
( Chofer ) )<br />
patente , rut _ chofer ( Movil rut fecha _ licencia _ hasta<<br />
01/<br />
01/<br />
1999<br />
S<strong>el</strong>ecciona todos los autos a cuyos choferes les caduca la licencia <strong>el</strong> 01/01/1999<br />
22
2.3. Cálculo r<strong>el</strong>acional <strong>de</strong> tuplas.<br />
El cálculo r<strong>el</strong>acional <strong>de</strong> tuplas <strong>de</strong>scribe la información <strong>de</strong>seada sin dar un<br />
procedimiento específico <strong>para</strong> obtenerla. Las <strong>consultas</strong> en <strong>el</strong> cálculo r<strong>el</strong>acional <strong>de</strong><br />
tuplas se expresan como<br />
{ t | P(t)},<br />
es <strong>de</strong>cir, son <strong>el</strong> conjunto <strong>de</strong> tuplas t tales que se cumple <strong>el</strong> predicado P <strong>para</strong> cada<br />
t. Siguiendo la misma notación, se utiliza t[A] <strong>para</strong> <strong>el</strong> valor <strong>de</strong> la tupla t en <strong>el</strong><br />
atributo A.<br />
{ t | t ∈ Dueño ∧ t[<br />
vigencia]<br />
= ' S '}<br />
{ t | t ∈ Movil ∧ t[<br />
patente]<br />
= ' HL −<br />
8483'<br />
}<br />
Si sólo se <strong>de</strong>sea obtener un atributo <strong>de</strong> la tupla, se utiliza <strong>el</strong> constructor<br />
“Existe” <strong>de</strong> la lógica matemática. Así, si lo que se <strong>de</strong>sea es <strong>el</strong> Nombre <strong>de</strong> los<br />
dueños <strong>de</strong> taxis que estén vigentes:<br />
{ t | ∃ s ∈ Dueño(<br />
t[<br />
Nombre]<br />
= s[<br />
Nombre]<br />
∧ s[<br />
vigencia]<br />
= ' S ' )}<br />
"Conjunto <strong>de</strong> todas las tuplas t tales que existe una tupla s en la r<strong>el</strong>ación<br />
Dueño <strong>para</strong> la que los valores <strong>de</strong> t y <strong>de</strong> s son iguales en <strong>el</strong> atributo Nombre y <strong>el</strong><br />
valor <strong>de</strong> s <strong>para</strong> <strong>el</strong> atributo vigencia = ‘S’ ". La variable <strong>de</strong> tupla t se <strong>de</strong>fine sólo en<br />
<strong>el</strong> atributo Nombre, puesto que éste es <strong>el</strong> único atributo <strong>para</strong> <strong>el</strong> que se especifica<br />
una condición <strong>para</strong> t. Así, <strong>el</strong> resultado es una r<strong>el</strong>ación sobre (Nombre).<br />
23
Si lo que se <strong>de</strong>sea es obtener las tarifas <strong>de</strong> todos los viajes que ha<br />
efectuado todos los móviles <strong>de</strong> marca “chevrolet”, la consulta requiere <strong>de</strong> dos<br />
cláusulas “Existe” conectadas por <strong>el</strong> operador <strong>de</strong> conjunción lógica “y”.<br />
{ t | ∃s<br />
∈ Viaje(<br />
t[<br />
tarifa ] = s[<br />
tarifa ] ∧<br />
∃u<br />
∈ Movil ( s[<br />
patente]<br />
= u[<br />
patente]<br />
∧ u[<br />
marca]<br />
= " chevrolet"<br />
))}<br />
Que se lee como <strong>el</strong> conjunto <strong>de</strong> todas las tuplas(tarifa) correspondientes a los<br />
viajes que han hecho todos los móviles <strong>de</strong> marca “chevrolet”.<br />
Considérese ahora la consulta “obtener todos los RUT <strong>de</strong> los dueños <strong>de</strong><br />
móviles, cuyos móviles no hayan efectuado nunca un viaje”:<br />
{ t | ∃s<br />
∈ Movil ( t[<br />
rut ] = s[<br />
Rut ] ∧<br />
¬∃u<br />
∈ Viaje(<br />
s[<br />
patente]<br />
= u[<br />
patente]))}<br />
que ocupa la cláusula “Existe” <strong>para</strong> exigir que <strong>el</strong> dueño posea un móvil y la<br />
cláusula “no existe” <strong>para</strong> <strong>el</strong>iminar a aqu<strong>el</strong>los móviles que tengan viajes realizados.<br />
La consulta que se presenta a continuación utiliza la implicación, la fórmula “P<br />
implica Q” significa que “si P es verdad entonces Q <strong>de</strong>be ser verdad”, se introduce<br />
<strong>el</strong> constructor “<strong>para</strong> todo”. Se <strong>de</strong>sea S<strong>el</strong>ecciona todos los autos a cuyos choferes<br />
les caduca la licencia <strong>el</strong> “01/01/1999”.<br />
{ t | ∀u<br />
∈ Chofer ( u[<br />
fecha _ licencia _ hasta ] < " 01 / 01 / 1999"<br />
⇒<br />
∃s<br />
∈ Movil ( t[<br />
patente]<br />
= s[<br />
patente]<br />
∧ s[<br />
rut _ chofer ] = u[<br />
rut ])) }<br />
Que es equivalente al ejemplo dado en <strong>el</strong> punto 2.2.6 (Diferencia).<br />
24
2.3.1. Definición Formal.<br />
Una expresión <strong>de</strong>l cálculo r<strong>el</strong>acional <strong>de</strong> tuplas es <strong>de</strong> la forma:<br />
{t|P(t)} don<strong>de</strong> P es una fórmula. En una fórmula pue<strong>de</strong>n aparecer varias variables<br />
<strong>de</strong> tuplas. Se dice que una variable <strong>de</strong> tupla es una variable libre a menos que<br />
este cuantificada por un ∃ o por un ∀ que entonces se dice variable ligada.<br />
Una fórmula en <strong>el</strong> cálculo r<strong>el</strong>acional <strong>de</strong> tuplas se compone <strong>de</strong> átomos. Un<br />
átomo tiene una <strong>de</strong> las siguientes formas:<br />
1. s ∈ r, don<strong>de</strong> s es una variable <strong>de</strong> tupla y r es una r<strong>el</strong>ación. No se permite la<br />
operación ∉.<br />
2. s[x] Θ u[y], don<strong>de</strong> s y u son variables <strong>de</strong> tuplas, x e y son atributos sobre los<br />
que están <strong>de</strong>finidos s y u respectivamente, y Θ es un operador <strong>de</strong> com<strong>para</strong>ción<br />
(=). Se requiere que los atributos x e y tengan dominios cuyos<br />
miembros puedan com<strong>para</strong>rse por medio <strong>de</strong> Θ.<br />
3. s[x] Θ c, don<strong>de</strong> s es una variable <strong>de</strong> tupla, x es una atributo sobre <strong>el</strong> que s esta<br />
<strong>de</strong>finida, Θ es un operador <strong>de</strong> com<strong>para</strong>ción, y c es una constante en <strong>el</strong> dominio<br />
<strong>de</strong>l atributo x.<br />
Ahora bien, Las fórmulas se construyen a partir <strong>de</strong> átomos usando las<br />
siguientes reglas:<br />
1. Un átomo es una fórmula.<br />
2. Si P1 es una fórmula, entonces también lo son ¬P1 y (P1).<br />
25
3. Si P1 y P2 son fórmulas, entonces también lo son P1∨P2, P1∧P2 y P1⇒P2.<br />
4. Si P1(s) es una fórmula que contiene una variable <strong>de</strong> tupla libre s y r es una<br />
r<strong>el</strong>ación, entonces:<br />
también son fórmulas.<br />
∃ s ∈ r (P1(s)) y ∀ s ∈ r (P1(s))<br />
2.3.2. Seguridad <strong>de</strong> expresiones.<br />
Una expresión <strong>de</strong>l cálculo r<strong>el</strong>acional <strong>de</strong> tuplas pue<strong>de</strong> generar r<strong>el</strong>aciones<br />
infinitas. Si por ejemplo se utiliza la construcción {t | ¬(t ∈ Dueño)} hay infinitas<br />
tuplas <strong>de</strong> personas que no son dueños <strong>de</strong> algún móvil, <strong>de</strong> hecho la mayoría <strong>de</strong><br />
estas tuplas ni siquiera pertenecen a la base <strong>de</strong> datos.<br />
Para ayudar a <strong>de</strong>finir las ligaduras <strong>de</strong>l cálculo r<strong>el</strong>acional <strong>de</strong> tuplas se<br />
introduce <strong>el</strong> concepto <strong>de</strong> dominio <strong>de</strong> fórmulas. De forma intuitiva, <strong>el</strong> dominio <strong>de</strong> la<br />
fórmula P (dom(p)) es <strong>el</strong> conjunto <strong>de</strong> todos los valores a los que P hace referencia.<br />
Esto incluye a todos los valores mencionados en P como todos los valores que<br />
aparezcan en las r<strong>el</strong>aciones referenciadas por P.<br />
Se dice que una expresión {t | P(t)} es segura si todos los valores que<br />
aparecen en <strong>el</strong> resultado son valores <strong>de</strong>l dominio <strong>de</strong> P.<br />
2.3.3. Potencia expresiva <strong>de</strong> los <strong>lenguaje</strong>s.<br />
El cálculo r<strong>el</strong>acional <strong>de</strong> tuplas restringido a expresiones seguras es<br />
equivalente en potencia expresiva al álgebra r<strong>el</strong>acional. Por lo tanto, <strong>para</strong> cada<br />
expresión <strong>de</strong>l álgebra r<strong>el</strong>acional hay una expresión equivalente en <strong>el</strong> cálculo<br />
r<strong>el</strong>acional <strong>de</strong> tuplas y viceversa. La <strong>de</strong>mostración <strong>de</strong> este hecho queda fuera <strong>de</strong><br />
los alcances <strong>de</strong> este trabajo, una prueba formal <strong>de</strong> la equivalencia entre <strong>el</strong> cálculo<br />
26
<strong>el</strong>acional <strong>de</strong> tuplas y <strong>el</strong> álgebra r<strong>el</strong>acional propuesta por E.F. Codd se pue<strong>de</strong><br />
encontrar en [Codd71].<br />
2.4. SQL como <strong>lenguaje</strong> <strong>de</strong> <strong>consultas</strong> r<strong>el</strong>acionales.<br />
2.4.1. Introducción.<br />
Los <strong>lenguaje</strong>s formales presentados en las secciones 2.2 y 2.3<br />
proporcionan una notación concisa <strong>para</strong> la representación <strong>de</strong> <strong>consultas</strong>. Sin<br />
embargo, los sistemas <strong>de</strong> base <strong>de</strong> datos necesitan un <strong>lenguaje</strong> <strong>de</strong> <strong>consultas</strong> más<br />
cómodo <strong>para</strong> <strong>el</strong> usuario. Aunque SQL se consi<strong>de</strong>re un <strong>lenguaje</strong> <strong>de</strong> <strong>consultas</strong>,<br />
contiene muchas otras capacida<strong>de</strong>s que incluyen características <strong>para</strong> <strong>de</strong>finir<br />
estructuras <strong>de</strong> datos, modificación <strong>de</strong> datos y la especificación <strong>de</strong> restricciones <strong>de</strong><br />
integridad.<br />
SQL se ha establecido como <strong>el</strong> <strong>lenguaje</strong> estándar <strong>de</strong> base <strong>de</strong> datos<br />
r<strong>el</strong>acionales. Hay numerosas versiones <strong>de</strong> SQL. La versión original se <strong>de</strong>sarrollo<br />
en <strong>el</strong> laboratorio <strong>de</strong> investigación <strong>de</strong> San Jose, California (San Jose Research<br />
Center) <strong>de</strong> IBM, este <strong>lenguaje</strong> originalmente <strong>de</strong>nominado Sequ<strong>el</strong>, se implementó<br />
como parte <strong>de</strong>l proyecto System R, a principios <strong>de</strong> 1970 [McJones97]. Des<strong>de</strong><br />
entonces ha evolucionado a lo que ahora se conoce como SQL (Structured Query<br />
Language, o <strong>lenguaje</strong> estructurado <strong>de</strong> <strong>consultas</strong>).<br />
En 1986, ANSI (American National Standards Institute, Instituto Nacional<br />
Americano <strong>de</strong> Normalización) e ISO (International Standards Organization,<br />
Organización Internacional <strong>de</strong> Normalización) Publicaron una norma <strong>de</strong> SQL<br />
<strong>de</strong>nominada SQL-86. En 1987 IBM publicó su propia norma <strong>de</strong> SQL <strong>de</strong>nominada<br />
SAA-SQL(System Application Architecture Database Interfaz, Interfaz <strong>de</strong> base <strong>de</strong><br />
datos <strong>para</strong> arquitecturas <strong>de</strong> aplicación <strong>de</strong> sistemas). En 1989 se publicó una<br />
27
norma extendida <strong>para</strong> SQL (SQL-89) y actualmente los SGBD son compatibles al<br />
menos con esta norma. La norma actual <strong>de</strong> SQL <strong>de</strong> ANSI/ISO es la SQL-92. Se<br />
<strong>de</strong>be tener en cuenta que algunas implementaciones <strong>de</strong> SQL pue<strong>de</strong>n ser<br />
compatibles sólo con SQL-89, no siéndolo con SQL-92.<br />
SQL proporciona dos tipos <strong>de</strong> <strong>lenguaje</strong>s diferentes: uno <strong>para</strong> especificar <strong>el</strong><br />
esquema r<strong>el</strong>acional y <strong>el</strong> otro <strong>para</strong> expresar las <strong>consultas</strong> y actualizaciones <strong>de</strong> la<br />
base <strong>de</strong> datos.<br />
2.4.2. Lenguaje <strong>de</strong> <strong>de</strong>finición <strong>de</strong> datos (DDL – Data Definition<br />
Language)<br />
Un esquema <strong>de</strong> bases <strong>de</strong> datos se representa mediante un sub<strong>lenguaje</strong><br />
especial llamado <strong>lenguaje</strong> <strong>de</strong> <strong>de</strong>finición <strong>de</strong> datos. El resultado <strong>de</strong> la compilación <strong>de</strong><br />
estas instrucciones es un conjunto <strong>de</strong> tablas, r<strong>el</strong>aciones y reglas cuyas<br />
<strong>de</strong>finiciones quedan almacenadas en un archivo (tabla u otro medio <strong>de</strong><br />
almacenamiento) que contiene “metadatos”, esto es, datos acerca <strong>de</strong> datos. Este<br />
archivo comúnmente llamado diccionario <strong>de</strong> datos (o catalogo <strong>de</strong>l sistema) es <strong>el</strong><br />
que se consulta toda vez que se quiere leer, modificar o <strong>el</strong>iminar los datos <strong>de</strong> la<br />
base <strong>de</strong> datos.<br />
28
2.4.3. Lenguaje <strong>de</strong> manipulación <strong>de</strong> datos (DML – Data Manipulation<br />
Language)<br />
Un D.M.L. es un sub<strong>lenguaje</strong> <strong>de</strong> consulta y manipulación <strong>de</strong> datos.<br />
Se enten<strong>de</strong>rá por manipulación <strong>de</strong> datos la :<br />
• Recuperación <strong>de</strong> Información.<br />
• Inserción <strong>de</strong> nueva Información.<br />
• Eliminación (Borrado) <strong>de</strong> información existente.<br />
• Modificación <strong>de</strong> Información Almacenada.<br />
2.4.4. Otras características <strong>de</strong> SQL.<br />
A<strong>de</strong>más <strong>de</strong> los dos tipos <strong>de</strong> sub<strong>lenguaje</strong>s mencionados anteriormente, SQL<br />
pue<strong>de</strong> ser utilizado <strong>para</strong> otras características propias que no poseen los <strong>lenguaje</strong>s<br />
formales <strong>de</strong> <strong>consultas</strong>, estas son:<br />
• Definición <strong>de</strong> vistas. El DDL <strong>de</strong> SQL incluye instrucciones <strong>para</strong> la<br />
<strong>de</strong>finición <strong>de</strong> vistas.<br />
• Autorización. El DDL <strong>de</strong> SQL incluye instrucciones <strong>para</strong> la<br />
especificación <strong>de</strong> los <strong>de</strong>rechos <strong>de</strong> acceso a los objetos <strong>de</strong> la base <strong>de</strong><br />
datos.<br />
• Integridad. El DDL <strong>de</strong> SQL también incluye un conjunto <strong>de</strong> sentencias<br />
<strong>para</strong> la especificación <strong>de</strong> restricciones <strong>de</strong> integridad.<br />
• Control <strong>de</strong> transacciones. SQL incluye or<strong>de</strong>nes <strong>para</strong> la especificación<br />
<strong>de</strong> los estados <strong>de</strong> una transacción, algunas implementaciones permiten<br />
29
a<strong>de</strong>más <strong>el</strong> bloqueo explicito <strong>de</strong> objetos <strong>de</strong> datos con <strong>el</strong> fin <strong>de</strong> manejar<br />
control <strong>de</strong> concurrencia.<br />
Para los efectos <strong>de</strong> este trabajo se anexa en <strong>el</strong> apéndice A una breve<br />
<strong>de</strong>scripción <strong>de</strong> los sub<strong>lenguaje</strong>s <strong>de</strong> Definición y manipulación <strong>de</strong> datos.<br />
30
Capítulo 3. Sistemas <strong>de</strong> Gestión <strong>de</strong> Bases <strong>de</strong> datos<br />
R<strong>el</strong>acionales.<br />
3.1. Introducción.<br />
Un Sistema <strong>de</strong> Gestión <strong>de</strong> Bases <strong>de</strong> datos (SGBD) consiste en una<br />
colección <strong>de</strong> datos interr<strong>el</strong>acionados y una colección <strong>de</strong> programas <strong>para</strong> acce<strong>de</strong>r a<br />
esos datos. El objetivo principal <strong>de</strong> un SGBD es proporcionar un entorno que sea<br />
tanto conveniente como eficiente <strong>para</strong> las personas que lo ocupan en <strong>el</strong><br />
almacenamiento y recuperación <strong>de</strong> la información.<br />
Los sistemas <strong>de</strong> bases <strong>de</strong> datos se diseñan <strong>para</strong> almacenar gran<strong>de</strong>s<br />
volúmenes <strong>de</strong> información, la gestión <strong>de</strong> los datos implica entonces la <strong>de</strong>finición<br />
<strong>de</strong> estructuras <strong>para</strong> <strong>el</strong> almacenamiento <strong>de</strong> la información y la provisión <strong>de</strong><br />
mecanismos <strong>para</strong> la manipulación <strong>de</strong> estos. A<strong>de</strong>más <strong>de</strong>ben proporcionar<br />
mecanismos <strong>de</strong> seguridad <strong>de</strong> los datos que protejan al sistema frente a caídas o a<br />
intentos <strong>de</strong> acceso <strong>de</strong> personas no autorizadas. Si los datos están compartidos<br />
por varios usuarios, <strong>el</strong> sistema <strong>de</strong>be asegurar la consistencia <strong>de</strong> los datos evitando<br />
posibles resultados anómalos.<br />
Un propósito principal <strong>de</strong> un sistema <strong>de</strong> bases <strong>de</strong> datos es proporcionar a<br />
los usuarios una visión abstracta <strong>de</strong> los datos. Esto se logra mediante la <strong>de</strong>finición<br />
<strong>de</strong> 3 niv<strong>el</strong>es <strong>de</strong> abstracción que pue<strong>de</strong>n ser observados: <strong>el</strong> niv<strong>el</strong> físico, <strong>el</strong> niv<strong>el</strong><br />
lógico y <strong>el</strong> niv<strong>el</strong> <strong>de</strong> vistas.<br />
El niv<strong>el</strong> físico es <strong>el</strong> niv<strong>el</strong> más bajo <strong>de</strong> abstracción, es <strong>el</strong> que <strong>de</strong>scribe como<br />
se almacenan los datos, a su vez, <strong>el</strong> niv<strong>el</strong> lógico <strong>de</strong>scribe que datos se<br />
almacenan realmente en la base <strong>de</strong> datos y que r<strong>el</strong>aciones existen entre estos<br />
31
datos. El niv<strong>el</strong> más alto <strong>de</strong> abstracción <strong>de</strong> datos es <strong>el</strong> niv<strong>el</strong> <strong>de</strong> vistas, <strong>el</strong> cual sólo<br />
presenta una <strong>de</strong>terminada porción <strong>de</strong> la base <strong>de</strong> datos, <strong>de</strong>pendiendo <strong>de</strong>l tipo <strong>de</strong><br />
usuario que la consulta, así, <strong>el</strong> sistema pue<strong>de</strong> proporcionar muchas vistas <strong>para</strong> la<br />
base <strong>de</strong> datos.<br />
Una base <strong>de</strong> datos sufre constantes cambios en <strong>el</strong> contenido <strong>de</strong> la<br />
información que contiene en <strong>el</strong> transcurso <strong>de</strong>l tiempo. La colección <strong>de</strong> datos<br />
almacenada en un momento particular se <strong>de</strong>nomina ejemplar <strong>de</strong> la base <strong>de</strong> datos.<br />
El diseño completo <strong>de</strong> la base <strong>de</strong> datos se llama esquema <strong>de</strong> la base <strong>de</strong> datos.<br />
La capacidad <strong>de</strong> modificar la <strong>de</strong>finición <strong>de</strong>l esquema en un niv<strong>el</strong> sin que<br />
afecte a una <strong>de</strong>finición <strong>de</strong> esquema en <strong>el</strong> niv<strong>el</strong> inmediatamente superior se<br />
<strong>de</strong>nomina in<strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong> datos. Existen 2 niv<strong>el</strong>es <strong>de</strong> in<strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong> datos:<br />
La in<strong>de</strong>pen<strong>de</strong>ncia física <strong>de</strong> datos y la in<strong>de</strong>pen<strong>de</strong>ncia lógica.<br />
La In<strong>de</strong>pen<strong>de</strong>ncia física <strong>de</strong> los datos se <strong>de</strong>scribe como la capacidad <strong>de</strong><br />
modificar <strong>el</strong> niv<strong>el</strong> físico <strong>de</strong> la base <strong>de</strong> datos sin tener que rescribir los programas<br />
<strong>de</strong> aplicación. En tanto la in<strong>de</strong>pen<strong>de</strong>ncia lógica se <strong>de</strong>fine como la capacidad <strong>de</strong><br />
modificar <strong>el</strong> esquema lógico sin causar que los programas <strong>de</strong> aplicación tengan<br />
que rescribirse.<br />
Un esquema <strong>de</strong> base <strong>de</strong> datos se especifica mediante un conjunto <strong>de</strong><br />
<strong>de</strong>finiciones expresadas en un DDL (Lenguaje <strong>de</strong> <strong>de</strong>finición <strong>de</strong> datos). El resultado<br />
<strong>de</strong> esta <strong>de</strong>finición es un conjunto <strong>de</strong> tablas y r<strong>el</strong>aciones que se almacenan en una<br />
tabla (o un conjunto <strong>de</strong> tablas) especial que se i<strong>de</strong>ntifica como <strong>el</strong> diccionario <strong>de</strong><br />
datos o <strong>el</strong> catálogo <strong>de</strong> la base <strong>de</strong> datos.<br />
Una transacción <strong>de</strong> base <strong>de</strong> datos se <strong>de</strong>fine como colección <strong>de</strong> operaciones<br />
que se lleva a cabo como una función lógica simple en una aplicación <strong>de</strong> base <strong>de</strong><br />
datos. Cada transacción es una unidad <strong>de</strong> atomicidad y consistencia. La<br />
32
atomicidad aquí se entien<strong>de</strong> como la capacidad <strong>de</strong> que muchas instrucciones se<br />
entiendan en ciertos casos como una sola, la consistencia se refiere a la<br />
capacidad <strong>de</strong> respetar las restricciones <strong>de</strong> consistencia <strong>de</strong> datos que posee la<br />
base <strong>de</strong> datos antes y <strong>de</strong>spués <strong>de</strong> ejecutar una transacción. El gestor <strong>de</strong><br />
transacciones es <strong>el</strong> responsable <strong>de</strong> asegurar que la base <strong>de</strong> datos permanezca en<br />
un estado consistente a pesar <strong>de</strong> los fallos <strong>de</strong>l sistema. El gestor <strong>de</strong> transacciones<br />
también asegura que la ejecución <strong>de</strong> transacciones concurrentes ocurran sin<br />
conflictos. El gestor <strong>de</strong> almacenamiento <strong>de</strong> la base <strong>de</strong> datos es un programa (o<br />
modulo) que proporciona la interfaz entre los datos <strong>de</strong> bajo niv<strong>el</strong> almacenados en<br />
la base <strong>de</strong> datos y los programas <strong>de</strong> aplicación y las <strong>consultas</strong> enviadas al<br />
sistema. El gestor <strong>de</strong> almacenamiento es <strong>el</strong> responsable <strong>de</strong> la interacción con los<br />
datos almacenados en disco.<br />
3.2. Transacciones, concurrencia y recuperación.<br />
3.2.1. Transacciones.<br />
Una transacción es una unidad <strong>de</strong> la ejecución <strong>de</strong> un programa que acce<strong>de</strong><br />
y posiblemente actualiza varios <strong>el</strong>ementos <strong>de</strong> datos. Se <strong>de</strong>limita <strong>de</strong>pendiendo <strong>de</strong>l<br />
<strong>lenguaje</strong> por las sentencias inicio transacción y fin transacción y se compone <strong>de</strong><br />
todas las instrucciones que se encuentran entre estos dos <strong>de</strong>limitadores.<br />
Para asegurar la consistencia <strong>de</strong> los datos se necesita que <strong>el</strong> sistema <strong>de</strong><br />
base <strong>de</strong> datos tengan las propieda<strong>de</strong>s llamadas ACID: (Atomicity, Consistency,<br />
Isolation, Durability - Atomicidad, Consistencia, Aislamiento, Durabilidad<br />
[Silberschatz97].<br />
La atomicidad asegura que o bien todos los efectos <strong>de</strong> la transacción se<br />
reflejan en la base <strong>de</strong> datos, o bien ninguno <strong>de</strong> <strong>el</strong>los; un fallo no pue<strong>de</strong> <strong>de</strong>jar a la<br />
base <strong>de</strong> datos en un estado en <strong>el</strong> cual una transacción se haya ejecutado<br />
33
parcialmente. La consistencia asegura que si la base <strong>de</strong> datos es consistente<br />
inicialmente, la ejecución <strong>de</strong> la transacción <strong>de</strong>ja la base <strong>de</strong> datos en un estado<br />
consistente. El aislamiento asegura que en la ejecución concurrente <strong>de</strong><br />
transacciones, estas están aisladas unas <strong>de</strong> otras, <strong>de</strong> tal manera que cada una<br />
tiene la impresión <strong>de</strong> que ninguna otra transacción se ejecuta concurrentemente<br />
con <strong>el</strong>la. La durabilidad asegura que una vez que la transacción se ha<br />
comprometido, las actualizaciones hechas por la transacción no se pier<strong>de</strong>n,<br />
incluso si hay un fallo en <strong>el</strong> sistema.<br />
Una transacción que termina con éxito se dice que está comprometida<br />
(commited), una transacción que haya sido comprometida llevará a la base <strong>de</strong><br />
datos a un nuevo estado consistente que <strong>de</strong>be permanecer incluso si hay un fallo<br />
en <strong>el</strong> sistema. En cualquier momento una transacción sólo pue<strong>de</strong> estar en uno <strong>de</strong><br />
los siguientes estados.<br />
• Activa (Active): <strong>el</strong> estado inicial; la transacción permanece en este estado<br />
durante su ejecución.<br />
• Parcialmente comprometida (Uncommited): Después <strong>de</strong> ejecutarse la ultima<br />
transacción.<br />
• Fallida (Failed): tras <strong>de</strong>scubrir que no se pue<strong>de</strong> continuar la ejecución normal.<br />
• Abortada (Rolled Back): <strong>de</strong>spués <strong>de</strong> haber retrocedido la transacción y<br />
restablecido la base <strong>de</strong> datos a su estado anterior al comienzo <strong>de</strong> la<br />
transacción.<br />
• Comprometida (Commited): tras completarse con éxito.<br />
Cuando varias transacciones se ejecutan concurrentemente, existe la<br />
posibilidad <strong>de</strong> que se pierda la consistencia <strong>de</strong> datos. Se hace necesario por lo<br />
tanto un sistema que controle la interacción entre las transacciones concurrentes.<br />
Puesto que una transacción por <strong>de</strong>finición conserva la consistencia, una ejecución<br />
34
lineal <strong>de</strong> transacciones la garantiza también. Un sistema que asegure esta<br />
propiedad se dice que asegura la secuencialidad.<br />
3.2.2. Concurrencia.<br />
Existen varios esquemas <strong>de</strong> control <strong>de</strong> concurrencia que aseguran la<br />
secuencialidad, todos estos esquemas o bien retrasan una operación o bien<br />
abortan la transacción que ha realizado la operación. Los más conocidos son los<br />
protocolos <strong>de</strong> bloqueo, <strong>el</strong> esquema <strong>de</strong> or<strong>de</strong>nación por marcas temporales, las<br />
técnicas <strong>de</strong> validación, <strong>el</strong> esquema <strong>de</strong> granularidad múltiple y los esquemas<br />
multiversión.<br />
Un protocolo <strong>de</strong> bloqueo es un conjunto <strong>de</strong> reglas que indican <strong>el</strong> momento<br />
en que una transacción pue<strong>de</strong> bloquear o <strong>de</strong>sbloquear un objeto <strong>de</strong> la base <strong>de</strong><br />
datos. El protocolo <strong>de</strong> bloqueo <strong>de</strong> dos fases permite que una transacción bloquee<br />
un objeto sólo <strong>de</strong>spués <strong>de</strong> que haya <strong>de</strong>sbloqueado otro objeto distinto, este<br />
método asegura la secuencialidad.<br />
El esquema <strong>de</strong> or<strong>de</strong>nación por marcas temporales asegura la<br />
secuencialidad s<strong>el</strong>eccionando previamente un or<strong>de</strong>n en todo par <strong>de</strong> transacciones.<br />
Existen 2 formas <strong>de</strong> implementar este esquema, uno es por medio <strong>de</strong> valores<br />
timestamp (<strong>de</strong>pendientes <strong>de</strong>l r<strong>el</strong>oj <strong>de</strong>l sistema) y por medio <strong>de</strong> un contador lógico<br />
que se incrementa cada vez que asigna una nueva marca temporal. Este<br />
protocolo asegura la secuencialidad en cuanto a conflictos y la ausencia <strong>de</strong><br />
interbloqueos, si una <strong>de</strong> las transacciones viola la norma la transacción se retrasa<br />
y se le asigna una nueva marca temporal. Por ejemplo, una operación leer se<br />
pue<strong>de</strong> retrasar porque todavía no se ha escrito <strong>el</strong> valor apropiado o incluso<br />
rechazar si ha sobrescrito <strong>el</strong> valor que supuestamente se iba a leer.<br />
35
Un esquema <strong>de</strong> validación es un método <strong>de</strong> control <strong>de</strong> concurrencia<br />
a<strong>de</strong>cuado <strong>para</strong> transacciones <strong>de</strong> sólo lectura y en las cuales la tasa <strong>de</strong> conflictos<br />
es baja. Se basa en dividir una transacción en 3 etapas (lectura, validación y<br />
escritura) y trabajar con <strong>el</strong> esquema <strong>de</strong> marcas temporales sobre la etapa <strong>de</strong><br />
validación. De esta manera se quita una sobrecarga en la etapa <strong>de</strong> lectura, en la<br />
cual no se necesita un esquema <strong>de</strong> control <strong>de</strong> concurrencia dado que toda lectura<br />
lleva a la base <strong>de</strong> datos al mismo estado <strong>de</strong> consistencia.<br />
Una manera distinta manejar la concurrencia es por medio <strong>de</strong> la<br />
granularidad, este concepto permite agrupar varios <strong>el</strong>ementos <strong>de</strong> datos y <strong>de</strong>finirlos<br />
como un todo <strong>para</strong> efectos <strong>de</strong> sincronización. Se <strong>de</strong>fine como una jerarquía <strong>de</strong><br />
distintos niv<strong>el</strong>es, don<strong>de</strong> <strong>el</strong> niv<strong>el</strong> superior pue<strong>de</strong> representar toda la base <strong>de</strong> datos,<br />
se esquematiza como estructura <strong>de</strong> árbol don<strong>de</strong> los nodos hijos <strong>de</strong> un nodo<br />
interno representan las <strong>de</strong>pen<strong>de</strong>ncias <strong>de</strong> datos asociadas. Se utilizan los tipos <strong>de</strong><br />
bloqueos Compartidos y Exclusivos más un nuevo tipo <strong>de</strong> bloqueo llamado <strong>el</strong><br />
bloqueo intencional, <strong>el</strong> cual indica que existen nodos <strong>de</strong>scendientes que tienen<br />
bloqueos compartidos o exclusivos.<br />
El esquema multiversión se basa en la creación <strong>de</strong> nuevas versiones <strong>de</strong> los<br />
<strong>el</strong>ementos <strong>de</strong> datos cada vez que una transacción vaya a escribir dicho <strong>el</strong>emento.<br />
Cuando se va a realizar una escritura <strong>el</strong> sistema <strong>el</strong>ige una <strong>de</strong> las versiones <strong>para</strong><br />
que se lea. El esquema <strong>de</strong> control <strong>de</strong> versiones garantiza que la versión que se va<br />
a leer se <strong>el</strong>ige <strong>de</strong> forma que asegure la secuencialidad por medio <strong>de</strong> marcas<br />
temporales. En este esquema una operación <strong>de</strong> lectura tiene éxito siempre, sin<br />
embargo, una operación <strong>de</strong> escritura pue<strong>de</strong> provocar <strong>el</strong> retroceso <strong>de</strong> una<br />
transacción.<br />
Un sistema está en estado <strong>de</strong> interbloqueo si existe un conjunto <strong>de</strong><br />
transacciones tal que toda transacción <strong>de</strong>l conjunto está esperando a otra<br />
transacción <strong>de</strong>l conjunto. En tal situación, ninguna <strong>de</strong> las transacciones pue<strong>de</strong><br />
36
progresar. Existen 2 métodos <strong>para</strong> tratar los interbloqueos y ambos provocan un<br />
retroceso <strong>de</strong> las transacciones, la diferencia radica en que uno es preventivo y otro<br />
curativo. El protocolo <strong>de</strong> prevención <strong>de</strong> interbloqueos asegura que <strong>el</strong> sistema<br />
nunca llegará a un estado <strong>de</strong> interbloqueos mientras que <strong>el</strong> método <strong>de</strong> <strong>de</strong>tección y<br />
recuperación <strong>de</strong> interbloqueos permite que <strong>el</strong> sistema llegue a un estado <strong>de</strong><br />
interbloqueos <strong>para</strong> luego tratar <strong>de</strong> recuperarse. La prevención se usa normalmente<br />
cuando la probabilidad <strong>de</strong> que <strong>el</strong> sistema llegue a un estado <strong>de</strong> interbloqueo es<br />
r<strong>el</strong>ativamente alta, <strong>de</strong> lo contrario lo más conveniente es usar la <strong>de</strong>tección y<br />
recuperación.<br />
3.2.3. Recuperación.<br />
Los fallos que ocurren en un computador pue<strong>de</strong>n darse por diferentes<br />
motivos (fallos <strong>de</strong> disco, cortes <strong>de</strong> energía o fallos en <strong>el</strong> software). En cada uno <strong>de</strong><br />
estos casos pue<strong>de</strong> per<strong>de</strong>rse información concerniente a la base <strong>de</strong> datos. Existen<br />
varios tipos <strong>de</strong> fallas, a consi<strong>de</strong>rar:<br />
• Fallo en la transacción, que a su vez se divi<strong>de</strong>n en errores lógicos y errores <strong>de</strong>l<br />
sistema. Un error lógico ocurre cuando una transacción no pue<strong>de</strong> continuar con<br />
su ejecución normal a causa <strong>de</strong> una condición interna como lo es un<br />
<strong>de</strong>sbordamiento o un exceso <strong>de</strong> recursos. Un error <strong>de</strong>l sistema ocurre cuando<br />
<strong>el</strong> sistema se encuentra en un estado no <strong>de</strong>seado como en <strong>el</strong> caso <strong>de</strong> los<br />
interbloqueos.<br />
• Caída <strong>de</strong>l sistema, provocado ya sea por <strong>el</strong> hardware, <strong>el</strong> sistema operativo o<br />
por <strong>el</strong> software <strong>de</strong> base <strong>de</strong> datos. Comúnmente causa la pérdida <strong>de</strong>l contenido<br />
<strong>de</strong> la memoria primaria y aborta <strong>el</strong> procesamiento <strong>de</strong> una transacción.<br />
37
• Fallo <strong>de</strong> disco, <strong>para</strong> <strong>el</strong> cual sólo sirve la recuperación por medio <strong>de</strong> copias<br />
existentes en medios <strong>de</strong> almacenamiento secundario como cintas magnéticas.<br />
La forma más aceptada <strong>de</strong> lograr un tipo <strong>de</strong> almacenamiento lo más estable<br />
posible es replicando la información en varios medios <strong>de</strong> almacenamiento no<br />
volátil, con modos <strong>de</strong> fallos in<strong>de</strong>pendientes. Los sistemas RAID (disposición<br />
redundante <strong>de</strong> discos in<strong>de</strong>pendientes) garantizan que <strong>el</strong> fallo <strong>de</strong> un sólo disco no<br />
conduzca a la perdida <strong>de</strong> datos. Sin embargo los sistemas RAID, no pue<strong>de</strong>n<br />
proteger al sistema <strong>de</strong> una pérdida <strong>de</strong> datos en <strong>el</strong> caso <strong>de</strong> una catástrofe<br />
geográfica, <strong>para</strong> tales efectos muchos sistemas <strong>de</strong> almacenamiento guardan<br />
copias <strong>de</strong> seguridad en cintas en otros lugares, no obstante, como las cintas no<br />
pue<strong>de</strong>n ser trasladadas continuamente, los últimos cambios realizados luego <strong>de</strong>l<br />
traslado <strong>de</strong> cintas no se pue<strong>de</strong>n volver a recuperar en <strong>el</strong> caso <strong>de</strong> tales <strong>de</strong>sastres.<br />
Los sistemas más seguros guardan copias <strong>de</strong> cada bloque <strong>de</strong> almacenamiento en<br />
otra disposición geográfica, datos que se transmiten por medios <strong>de</strong> re<strong>de</strong>s <strong>de</strong><br />
computadores al sistema <strong>de</strong> respaldo remoto.<br />
El estado <strong>de</strong> un sistema <strong>de</strong> base <strong>de</strong> datos pue<strong>de</strong> no volver a ser consistente<br />
en caso <strong>de</strong> que ocurran fallos, <strong>para</strong> preservar la consistencia es necesario que<br />
cada transacción sea atómica. Garantizar la propiedad <strong>de</strong> atomicidad es<br />
responsabilidad <strong>de</strong>l esquema <strong>de</strong> recuperación.<br />
Existen básicamente 2 esquemas que garantizan la atomicidad.<br />
Basados en <strong>el</strong> registro histórico 4 . Todas las modificaciones se graban en <strong>el</strong><br />
registro histórico, <strong>el</strong> cual <strong>de</strong>be estar guardado en almacenamiento estable. En <strong>el</strong><br />
esquema <strong>de</strong> modificación diferida, durante la ejecución <strong>de</strong> una transacción, se<br />
difieren todas las operaciones <strong>de</strong> escritura hasta que la transacción se<br />
4 Comúnmente llamado log <strong>de</strong> transacciones.<br />
38
compromete parcialmente, momento en <strong>el</strong> cual se utiliza la información <strong>de</strong>l registro<br />
histórico asociado con la transacción <strong>para</strong> ejecutar las escrituras diferidas. Con la<br />
técnica <strong>de</strong> modificación inmediata todas las modificaciones se aplican<br />
directamente en la base <strong>de</strong> datos. Si ocurre una caída se utiliza la información <strong>de</strong>l<br />
registro histórico <strong>para</strong> llevar a la base <strong>de</strong> datos a un estado estable previo.<br />
Paginación en la sombra. Durante la vida <strong>de</strong> una transacción se mantienen<br />
2 tablas <strong>de</strong> páginas: la tabla actual <strong>de</strong> páginas y la tabla <strong>de</strong> páginas sombra.<br />
Ambas tablas son idénticas al principio <strong>de</strong> la transacción, sin embargo, la tabla<br />
actual <strong>de</strong> páginas pue<strong>de</strong> ir cambiando luego <strong>de</strong> cada operación escribir. Todas las<br />
operaciones <strong>de</strong> lectura y escritura utilizan la tabla <strong>de</strong> páginas actual, cuando una<br />
transacción se compromete parcialmente se <strong>de</strong>secha la tabla <strong>de</strong> páginas sombra y<br />
la tabla actual se convierte en la nueva tabla <strong>de</strong> páginas. Si la transacción fracasa,<br />
simplemente se <strong>de</strong>secha la tabla actual <strong>de</strong> páginas.<br />
El procesamiento <strong>de</strong> transacciones se basa en un mo<strong>de</strong>lo <strong>de</strong><br />
almacenamiento en <strong>el</strong> cual la memoria principal contiene una memoria intermedia<br />
<strong>para</strong> <strong>el</strong> registro histórico, una memoria intermedia <strong>para</strong> la base <strong>de</strong> datos y una<br />
memoria intermedia <strong>para</strong> <strong>el</strong> sistema. Una implementación eficiente <strong>de</strong> un<br />
esquema <strong>de</strong> recuperación <strong>de</strong> datos requiere que sea mínimo <strong>el</strong> número <strong>de</strong><br />
escrituras <strong>de</strong> la base <strong>de</strong> datos y que sea realizado en almacenamiento estable.<br />
Los registros <strong>de</strong>l registro histórico pue<strong>de</strong>n guardarse inicialmente en la memoria<br />
intermedia <strong>de</strong>l registro histórico pero <strong>de</strong>ben ser llevados a almacenamiento estable<br />
bajo dos situaciones:<br />
a) <strong>de</strong>ben escribirse en almacenamiento estable todos los registros <strong>de</strong>l registro<br />
histórico que referencien a la transacción Ti antes <strong>de</strong> grabar <strong>el</strong> registro que<br />
indique que la transacción Ti ha sido comprometida<br />
39
) <strong>de</strong>ben escribirse en almacenamiento estable todos los registros <strong>de</strong>l registro<br />
histórico pertenecientes a los datos <strong>de</strong> un bloque antes <strong>de</strong> que ese bloque <strong>de</strong><br />
datos se escriba <strong>de</strong>s<strong>de</strong> la memoria intermedia a la base <strong>de</strong> datos.<br />
3.3. Tipos <strong>de</strong> SGBD.<br />
La arquitectura <strong>de</strong> un sistema <strong>de</strong> base <strong>de</strong> datos está influenciada por <strong>el</strong><br />
sistema informático que soporta la instalación <strong>de</strong>l SGBD, lo que reflejará muchas<br />
<strong>de</strong> las características propias <strong>de</strong>l sistema subyacente en <strong>el</strong> SGBD.<br />
La re<strong>de</strong>s <strong>de</strong> computadores permiten se<strong>para</strong>r tareas en un esquema <strong>de</strong><br />
clientes y servidores, <strong>el</strong> procesamiento <strong>para</strong>l<strong>el</strong>o <strong>de</strong>ntro <strong>de</strong>l computador permite<br />
ac<strong>el</strong>erar algunas <strong>de</strong> las tareas <strong>de</strong> la base <strong>de</strong> datos así como la posibilidad <strong>de</strong><br />
ejecutar más transacciones por segundo. Las <strong>consultas</strong> se pue<strong>de</strong>n <strong>para</strong>l<strong>el</strong>izar<br />
permitiendo así que una consulta se pueda ejecutar por más <strong>de</strong> un procesador al<br />
mismo tiempo, esta característica ha llevado al estudio <strong>de</strong> las bases <strong>de</strong> datos<br />
<strong>para</strong>l<strong>el</strong>as.<br />
La distribución <strong>de</strong> datos a través <strong>de</strong> distintos <strong>de</strong>partamentos <strong>de</strong> una<br />
organización permite que <strong>el</strong>los residan don<strong>de</strong> han sido generados (y don<strong>de</strong> se<br />
entien<strong>de</strong> que son más requeridos); la i<strong>de</strong>a <strong>de</strong> mantener una copia <strong>de</strong> estos datos<br />
en otros lugares permite que puedan seguir las operaciones sobre los datos aún si<br />
alguno <strong>de</strong> estos sitios sufre algún <strong>de</strong>sastre. El estudio <strong>de</strong> este tipo <strong>de</strong><br />
<strong>de</strong>scentralización <strong>de</strong> los datos lleva al <strong>de</strong>sarrollo <strong>de</strong> los sistemas <strong>de</strong> base <strong>de</strong> datos<br />
distribuidos.<br />
3.3.1. SGBD centralizados.<br />
40
Un sistema <strong>de</strong> base <strong>de</strong> datos centralizado es aqu<strong>el</strong> que se ejecuta en un<br />
único sistema computacional sin tener, <strong>para</strong> tal efecto, que interactuar con otros<br />
computadores. El rango <strong>de</strong> estos sistemas compren<strong>de</strong> <strong>de</strong>s<strong>de</strong> los sistemas <strong>de</strong><br />
bases <strong>de</strong> datos monousuario ejecutándose en computadores personales hasta los<br />
sistemas <strong>de</strong> bases <strong>de</strong> datos ejecutándose en sistemas <strong>de</strong> alto rendimiento.<br />
Normalmente los sistemas <strong>de</strong> base <strong>de</strong> datos monousuarios no su<strong>el</strong>en<br />
proporcionar muchas <strong>de</strong> las facilida<strong>de</strong>s que ofrecen los sistemas multiusuario, en<br />
particular no tienen control <strong>de</strong> concurrencia y tienen precarios o inexistentes<br />
sistemas <strong>de</strong> recuperación.<br />
Dado que las maquinas en las cuales se utilizan los sistemas monousuarios<br />
son comúnmente computadores <strong>de</strong> propósito general, la arquitectura <strong>de</strong> estas<br />
maquinas es siempre parecida(<strong>de</strong> 1 a 2 procesadores que comparten la memoria<br />
principal) por tanto los sistemas <strong>de</strong> base <strong>de</strong> datos que se ejecutan sobre estas<br />
maquinas no intentan dividir una consulta simple entre los distintos procesadores,<br />
sino que ejecutan cada consulta en un único procesador posibilitando así la<br />
concurrencia <strong>de</strong> varias <strong>consultas</strong>. Este tipo <strong>de</strong> sistemas dan la sensación <strong>de</strong> una<br />
mayor productividad (puesto que pue<strong>de</strong>n ejecutar un mayor número <strong>de</strong><br />
transacciones por segundo) a pesar <strong>de</strong> que cada transacción individualmente no<br />
se ejecute más rápido. Por <strong>el</strong> contrario las máquinas <strong>para</strong>l<strong>el</strong>as tienen un gran<br />
número <strong>de</strong> procesadores y los sistemas <strong>de</strong> base <strong>de</strong> datos que ahí se ejecutan<br />
siempre ten<strong>de</strong>rán a <strong>para</strong>l<strong>el</strong>izar las tareas simples (<strong>consultas</strong>) que solicitan los<br />
usuarios.<br />
3.3.2. SGBD Cliente-Servidor.<br />
Con <strong>el</strong> crecimiento <strong>de</strong> los computadores personales (PC) y <strong>de</strong> las re<strong>de</strong>s <strong>de</strong><br />
área local (LAN), se han ido <strong>de</strong>splazando hacia <strong>el</strong> lado <strong>de</strong>l cliente la funcionalidad<br />
<strong>de</strong> la parte visible al usuario <strong>de</strong> la base <strong>de</strong> datos (interfaces <strong>de</strong> formularios, gestión<br />
41
<strong>de</strong> informes, etc.) <strong>de</strong> modo que los sistemas servidores provean la parte<br />
subyacente que tiene que ver con <strong>el</strong> acceso a las estructuras <strong>de</strong> datos, evaluación<br />
y procesamiento <strong>de</strong> <strong>consultas</strong>, control <strong>de</strong> concurrencia y recuperación. Los<br />
sistemas servidores pue<strong>de</strong>n dividirse en 2 tipos: los servidores transaccionales<br />
(que sirven <strong>para</strong> agrupar la lógica <strong>de</strong>l negocio en un servicio aparte, proveen una<br />
interfaz a través <strong>de</strong> la cual los clientes pue<strong>de</strong>n enviar peticiones como lo son<br />
ODBC 5 o RPC 6 ) y los servidores <strong>de</strong> datos(los cuales envían datos a más bajo niv<strong>el</strong><br />
y que <strong>de</strong>scansan en la capacidad <strong>de</strong> procesamiento <strong>de</strong> datos <strong>de</strong> las maquinas<br />
clientes).<br />
Existen 2 arquitecturas dominantes en la construcción <strong>de</strong> motores <strong>de</strong> base<br />
<strong>de</strong> datos cliente-servidor: los motores multiprocesos y los motores multihilos.<br />
3.3.2.1. Motores <strong>de</strong> base <strong>de</strong> datos multiprocesos (Multi-process database<br />
engines).<br />
Algunos motores <strong>de</strong> base <strong>de</strong> datos confían en múltiples aplicaciones <strong>para</strong><br />
realizar su trabajo. En este tipo <strong>de</strong> arquitectura, cada vez que un usuario se<br />
conecta a la base <strong>de</strong> datos, ésta inicia una nueva instancia <strong>de</strong> la aplicación <strong>de</strong><br />
base <strong>de</strong> datos. Con <strong>el</strong> fin <strong>de</strong> coordinar a muchos usuarios que accesan los mismos<br />
conjuntos <strong>de</strong> datos estos ejecutables trabajan con un coordinador global <strong>de</strong> tareas<br />
que planifica operaciones <strong>para</strong> todos los usuarios. La comunicación entre<br />
aplicaciones <strong>de</strong> este tipo se realiza por medio <strong>de</strong> un sistema propietario <strong>de</strong><br />
comunicaciones interprocesos (IPC).<br />
5 Open database conectivity: API <strong>de</strong> acceso a datos que soporta <strong>el</strong> acceso a cualquier<br />
fuente <strong>de</strong> datos <strong>para</strong> la cual exista un driver ODBC. ODBC se encuadra <strong>de</strong>ntro <strong>de</strong> los estándares<br />
ANSI e ISO <strong>para</strong> la Interfaz <strong>de</strong> llamadas <strong>de</strong> datos (CLI).<br />
6 Remote procedure call: Una forma <strong>de</strong> comunicación entre aplicaciones que escon<strong>de</strong> la<br />
complejidad <strong>de</strong> la red utilizando un mecanismo <strong>de</strong> llamada <strong>de</strong> procedimientos ordinario. Es un<br />
proceso sincrónico firmemente acoplado.<br />
42
El ejemplo más popular <strong>de</strong> motores <strong>de</strong> base <strong>de</strong> datos multiprocesos es <strong>el</strong><br />
Oracle Server (Oracle corporation) <strong>el</strong> cual carga 16 tipos <strong>de</strong> ejecutables distintos<br />
que realizan distintas tareas. El sistema ejecuta sus aplicaciones que sirven <strong>para</strong><br />
administrar <strong>el</strong> acceso <strong>de</strong> múltiples usuarios a las tablas, <strong>el</strong> registro y control <strong>de</strong><br />
versiones <strong>de</strong> una transacción y otras características como la replicación <strong>de</strong> datos,<br />
transacciones distribuidas. Por otro lado, cuando una conexión a la base <strong>de</strong> datos<br />
se establece, <strong>el</strong> sistema carga los ejecutables r<strong>el</strong>acionados a tareas <strong>de</strong> usuario.<br />
Cada vez que un usuario se conecta a una base <strong>de</strong> datos Oracle, esta<br />
carga un ejecutable con una nueva instancia <strong>de</strong> la base <strong>de</strong> datos, las <strong>consultas</strong> <strong>de</strong><br />
usuario son transmitidas a este ejecutable, <strong>el</strong> cual trabaja en conjunto con otros<br />
ejecutables en <strong>el</strong> servidor que retornan conjuntos <strong>de</strong> datos, manejan los bloqueos<br />
y ejecutan todas las funciones necesarias <strong>para</strong> <strong>el</strong> acceso <strong>de</strong> datos.<br />
La mayoría <strong>de</strong> los motores <strong>de</strong> base <strong>de</strong> datos multiprocesos fueron<br />
<strong>de</strong>sarrollados antes <strong>de</strong> que los sistemas operativos soportaran características<br />
tales como hilos o planificación <strong>de</strong> tareas (scheduling). Como resultado <strong>de</strong> esto, <strong>el</strong><br />
hecho <strong>de</strong> <strong>de</strong>scomponer una operación significaba escribir un ejecutable distinto<br />
<strong>para</strong> manejar esta operación. Esta característica proporciona <strong>el</strong> beneficio <strong>de</strong> la<br />
fácil escalabilidad a través <strong>de</strong> la adición <strong>de</strong> más CPUs.<br />
En un ambiente <strong>de</strong> multitarea <strong>el</strong> sistema operativo divi<strong>de</strong> <strong>el</strong> tiempo <strong>de</strong><br />
procesamiento entre múltiples aplicaciones asignándoles una porción <strong>de</strong> tiempo<br />
<strong>de</strong> CPU (“slice”) a cada una. De esta manera siempre hay una sola tarea<br />
ejecutándose a la vez, sin embargo <strong>el</strong> resultado es que múltiples aplicaciones<br />
aparenten estar corriendo simultáneamente en una sola CPU. La ventaja real, sin<br />
embargo, viene cuando <strong>el</strong> sistema operativo cuenta con múltiples CPUs.<br />
43
3.3.2.2. Motores <strong>de</strong> base <strong>de</strong> datos multihilos (Single-Process multi-threa<strong>de</strong>d<br />
database engines).<br />
Los motores <strong>de</strong> base <strong>de</strong> datos multihilos abordan <strong>el</strong> problema <strong>de</strong>l acceso<br />
multiusuario <strong>de</strong> una manera distinta, pero con principios similares. En lugar <strong>de</strong><br />
confiar en que <strong>el</strong> sistema operativo comparta los recursos <strong>de</strong> procesamiento, <strong>el</strong><br />
motor toma la responsabilidad por sí mismo, lo que en la práctica se asocia a una<br />
mejor portabilidad <strong>de</strong>l sistema. Motores <strong>de</strong> base <strong>de</strong> datos comerciales como<br />
Sybase Adaptive Server o Microsoft Sql Server son ejemplos <strong>de</strong> este enfoque.<br />
Las ventajas <strong>de</strong> este tipo <strong>de</strong> motores radican en una mayor eficiencia en <strong>el</strong><br />
uso <strong>de</strong> recursos <strong>para</strong> <strong>de</strong>terminadas plataformas. Mientas un sistema<br />
multiprocesos consume entre 500 Kb y 1 Mb por conexión, un motor multihilos<br />
consume entre 50 y 100 Kb <strong>de</strong> RAM diferencia que pue<strong>de</strong> ser utilizada en caché<br />
<strong>de</strong> datos y procedimientos. Otra ventaja es que no hay necesidad <strong>de</strong> un<br />
mecanismo <strong>de</strong> comunicación interprocesos.<br />
De esta manera, la base <strong>de</strong> datos utiliza un <strong>el</strong>emento finito <strong>de</strong> trabajo, (<strong>el</strong><br />
hilo) <strong>para</strong> una variedad <strong>de</strong> operaciones (instrucciones <strong>de</strong> usuarios, bloqueos <strong>de</strong><br />
datos, E/S <strong>de</strong> disco, administración <strong>de</strong>l caché, etc.) en vez <strong>de</strong> utilizar aplicaciones<br />
especializadas <strong>para</strong> cada tarea.<br />
Las <strong>de</strong>sventajas más reconocidas son dos: escalabilidad y portabilidad. La<br />
escalabilidad se centra en la habilidad que tengan los distintos motores <strong>de</strong> base <strong>de</strong><br />
datos multihilos <strong>de</strong> <strong>de</strong>scomponer una operación <strong>de</strong> manera que múltiples tareas<br />
puedan ejecutar esta operación.<br />
Los problemas <strong>de</strong> portabilidad guardan r<strong>el</strong>ación con <strong>el</strong> SMP<br />
(multiprocesamiento simétrico) y se originan en <strong>el</strong> hecho <strong>de</strong> que dado que<br />
diferentes fabricantes <strong>de</strong> hardware dan soporte a SMP <strong>de</strong> diferentes maneras,<br />
44
estos motores <strong>de</strong> base <strong>de</strong> datos han tenido que implementar técnicas neutras que<br />
buscan funcionar bien en cualquier implementación física, lo que conlleva una<br />
sobrecarga en <strong>el</strong> motor y una limitación en la habilidad <strong>de</strong> escalar a un gran<br />
número <strong>de</strong> procesadores.<br />
3.3.3. SGBD Paral<strong>el</strong>os.<br />
Los sistemas <strong>para</strong>l<strong>el</strong>os <strong>de</strong> base <strong>de</strong> datos constan <strong>de</strong> varios procesadores y<br />
varios discos conectados a través <strong>de</strong> una red <strong>de</strong> interconexión <strong>de</strong> alta v<strong>el</strong>ocidad.<br />
Para medir <strong>el</strong> rendimiento <strong>de</strong> los sistemas <strong>de</strong> base <strong>de</strong> datos existen 2 medidas<br />
principales: la primera es la productividad (throughput) que se entien<strong>de</strong> como <strong>el</strong><br />
número <strong>de</strong> tareas que pue<strong>de</strong>n completarse en un intervalo <strong>de</strong> tiempo <strong>de</strong>terminado.<br />
La segunda es <strong>el</strong> tiempo <strong>de</strong> respuesta (response time) que es la cantidad <strong>de</strong><br />
tiempo que necesita <strong>para</strong> completar una única tarea a partir <strong>de</strong>l momento en que<br />
se envíe. Un sistema que procese un gran número <strong>de</strong> pequeñas transacciones<br />
pue<strong>de</strong> mejorar su productividad realizando muchas transacciones en <strong>para</strong>l<strong>el</strong>o. Un<br />
sistema que procese transacciones más largas pue<strong>de</strong> mejorar tanto su<br />
productividad como sus tiempos <strong>de</strong> respuesta realizando en <strong>para</strong>l<strong>el</strong>o cada una <strong>de</strong><br />
las subtareas <strong>de</strong> cada transacción.<br />
Las ganancias en este tipo <strong>de</strong> SGBD se pue<strong>de</strong>n dar en términos <strong>de</strong> v<strong>el</strong>ocidad<br />
(menor tiempo <strong>de</strong> ejecución <strong>para</strong> una tarea dada) y ampliabilidad (capacidad <strong>de</strong><br />
procesar tareas más largas en <strong>el</strong> mismo tiempo).<br />
Existen varios mo<strong>de</strong>los <strong>de</strong> arquitecturas <strong>para</strong> maquinas <strong>para</strong>l<strong>el</strong>as, los más<br />
mencionados son:<br />
• Memoria Compartida : Todos los procesadores comparten una memoria<br />
común.<br />
45
• Disco Compartido: Todos los procesadores comparten una disposición <strong>de</strong><br />
discos común.<br />
• Sin Compartimiento: Los procesadores no comparten ni memoria ni disco.<br />
• Jerárquico: Compartimiento tanto <strong>de</strong> memoria como <strong>de</strong> disco.<br />
3.3.4. SGBD Distribuidos.<br />
En un SGBD distribuido, la base <strong>de</strong> datos se almacena en varios<br />
computadores que se pue<strong>de</strong>n comunicar a sus vez por distintos medios <strong>de</strong><br />
comunicación (<strong>de</strong>s<strong>de</strong> re<strong>de</strong>s <strong>de</strong> alta v<strong>el</strong>ocidad a líneas t<strong>el</strong>efónicas). No comparten<br />
memoria ni discos y sus tamaños pue<strong>de</strong>n variar tanto como sus funciones<br />
pudiendo abarcar <strong>de</strong>s<strong>de</strong> PC hasta gran<strong>de</strong>s sistemas. Se <strong>de</strong>nomina con <strong>el</strong> término<br />
<strong>de</strong> emplazamientos o nodos a todos aqu<strong>el</strong>los computadores que pertenecen a un<br />
sistema distribuido.<br />
Las principales diferencias entre las bases <strong>de</strong> datos <strong>para</strong>l<strong>el</strong>as y las bases<br />
<strong>de</strong> datos distribuidas son las siguientes: las bases <strong>de</strong> datos distribuidas se<br />
encuentran normalmente en varios lugares geográficos distintos, se administran<br />
<strong>de</strong> forma se<strong>para</strong>da y poseen una interconexión más lenta. Otra diferencia es que<br />
en un sistema distribuido se dan dos tipos <strong>de</strong> transacciones, las locales y las<br />
globales. Una transacción local es aqu<strong>el</strong>la que acce<strong>de</strong> a los datos <strong>de</strong>l único<br />
emplazamiento en <strong>el</strong> cual se inició la transacción. Por otra parte una transacción<br />
global es aqu<strong>el</strong>la que o bien acce<strong>de</strong> a los datos situados en un emplazamiento<br />
diferente <strong>de</strong> aqu<strong>el</strong> en <strong>el</strong> que se inició la transacción, o bien acce<strong>de</strong> a datos <strong>de</strong><br />
varios emplazamientos distintos.<br />
Un sistema <strong>de</strong> base <strong>de</strong> datos distribuido se conoce por:<br />
• Los distintos emplazamientos están informados <strong>de</strong> los <strong>de</strong>más.<br />
46
• Aunque algunas r<strong>el</strong>aciones pue<strong>de</strong>n estar almacenadas sólo en algunos<br />
emplazamientos, éstos comparten un esquema global común.<br />
• Cada emplazamiento proporciona un entorno <strong>para</strong> la ejecución <strong>de</strong><br />
transacciones tanto locales como globales.<br />
47
Capítulo 4. Introducción al Procesamiento <strong>de</strong> Consultas,<br />
El enfoque <strong>de</strong> System R.<br />
4.1. Introducción.<br />
El Procesamiento <strong>de</strong> <strong>consultas</strong> hace referencia a la serie <strong>de</strong> activida<strong>de</strong>s a<br />
seguir <strong>para</strong> llevar a cabo la recuperación <strong>de</strong> datos <strong>de</strong>s<strong>de</strong> una base <strong>de</strong> datos. Estas<br />
activida<strong>de</strong>s incluyen la traducción <strong>de</strong> <strong>consultas</strong> en <strong>lenguaje</strong>s <strong>de</strong> <strong>consultas</strong> <strong>de</strong> alto<br />
niv<strong>el</strong> (Ej: SQL) a expresiones que se puedan implementar en un niv<strong>el</strong> físico, así<br />
como también los algoritmos <strong>de</strong> evaluación y optimización <strong>de</strong> <strong>consultas</strong>.<br />
Una <strong>de</strong> las ventajas principales <strong>de</strong>l mo<strong>de</strong>lo r<strong>el</strong>acional presentado por Codd<br />
en 1970 es la que tiene r<strong>el</strong>ación con la in<strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong> los datos que se<br />
entien<strong>de</strong> aquí como la se<strong>para</strong>ción entre <strong>el</strong> mo<strong>de</strong>lo (lógico) y la implementación<br />
(física). Esta se<strong>para</strong>ción nos permite <strong>de</strong>sarrollar una po<strong>de</strong>rosa semántica lógica<br />
in<strong>de</strong>pendiente <strong>de</strong> una implementación física particular.<br />
Uno <strong>de</strong> los <strong>de</strong>safíos <strong>de</strong> la in<strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong> datos es que la codificación <strong>de</strong><br />
una consulta <strong>para</strong> la base <strong>de</strong> datos se componga <strong>de</strong> 2 fases:<br />
1. La <strong>de</strong>scripción lógica <strong>de</strong> la consulta (que se supone que <strong>de</strong>be hacer).<br />
2. La <strong>de</strong>finición <strong>de</strong>l plan <strong>de</strong> ejecución físico (<strong>el</strong> que muestra como implementar la<br />
consulta).<br />
Antes <strong>de</strong> empezar <strong>el</strong> Procesamiento <strong>de</strong> la consulta <strong>el</strong> sistema <strong>de</strong>be traducir<br />
la consulta a un medio <strong>de</strong> representación interno con <strong>el</strong> cual le sea fácil operar.<br />
48
Así, por ejemplo <strong>para</strong> SQL la representación más útil es la <strong>de</strong>l álgebra r<strong>el</strong>acional<br />
extendida (árbol r<strong>el</strong>acional). Este proceso cumple la misma función que <strong>el</strong><br />
analizador léxico y sintáctico <strong>de</strong> un compilador, es <strong>de</strong>cir, revisa la sintaxis <strong>de</strong> la<br />
consulta y chequea que todos lo i<strong>de</strong>ntificadores sean nombres <strong>de</strong> objetos <strong>de</strong> la<br />
base <strong>de</strong> datos, en <strong>el</strong> caso <strong>de</strong> las vistas reemplaza <strong>el</strong> nombre <strong>de</strong> la vista por la<br />
expresión r<strong>el</strong>acional que la representa.<br />
El plan <strong>de</strong> ejecución es un árbol r<strong>el</strong>acional armado a partir <strong>de</strong> la consulta y<br />
que sólo pue<strong>de</strong> ser entendido por <strong>el</strong> motor <strong>de</strong> ejecución <strong>de</strong> <strong>consultas</strong>. La<br />
transformación <strong>de</strong> la consulta a un plan pue<strong>de</strong> ser hecha efectivamente a mano y<br />
en algunos casos <strong>de</strong> <strong>consultas</strong> simples que se ejecutan miles <strong>de</strong> veces esta<br />
podría ser la mejor estrategia, sin embargo, una <strong>de</strong> las ventajas que nos ofrece <strong>el</strong><br />
mo<strong>de</strong>lo r<strong>el</strong>acional es la capacidad <strong>de</strong> usar la información <strong>de</strong>l catalogo <strong>de</strong> la base<br />
<strong>de</strong> datos, que como se verá más a<strong>de</strong>lante, podrá respon<strong>de</strong>r una gran cantidad <strong>de</strong><br />
preguntas distintas.<br />
Por otro lado, aunque una consulta simple pueda ser ejecutada miles <strong>de</strong><br />
veces, no existe un camino mecánico que garantice que <strong>el</strong> plan <strong>de</strong> ejecución<br />
<strong>el</strong>egido satisfaga la consulta que se quiere implementar, puesto que:<br />
1. Un Plan calculado a mano (o un plan precalculado) será invalidado por<br />
cambios lógicos <strong>de</strong>ntro <strong>de</strong>l esquema o por cambios físicos en <strong>el</strong> camino <strong>de</strong><br />
acceso a la información o en <strong>el</strong> almacenamiento físico.<br />
2. Si los parámetros <strong>de</strong> la consulta (o los datos) cambian, la r<strong>el</strong>ación optima que<br />
asocia a un plan con una consulta por sobre otros pue<strong>de</strong> cambiar.<br />
La siguiente figura nos muestra los pasos en <strong>el</strong> procesamiento <strong>de</strong> una<br />
consulta.<br />
49
Consulta<br />
Resultado<br />
<strong>de</strong> la Consulta<br />
Analizador y<br />
traductor<br />
(parser)<br />
Datos<br />
Motor <strong>de</strong><br />
Ejecución<br />
Información <strong>de</strong>l<br />
Catalogo<br />
Figura 4-1 - Pasos en <strong>el</strong> procesamiento <strong>de</strong> una consulta SQL<br />
Expresión en Algebra<br />
R<strong>el</strong>acional<br />
(Arbol r<strong>el</strong>acional)<br />
Optimizador<br />
Plan <strong>de</strong><br />
Ejecución<br />
Después <strong>de</strong> enviar la consulta, la base <strong>de</strong> datos <strong>de</strong>be producir su<br />
correspondiente plan <strong>de</strong> ejecución. El primer paso en este proceso es traducir la<br />
consulta <strong>de</strong>s<strong>de</strong> SQL a un árbol lógico en álgebra r<strong>el</strong>acional, proceso comúnmente<br />
llamado parser.<br />
El Próximo paso es traducir <strong>el</strong> árbol <strong>de</strong> la consulta en <strong>el</strong> plan <strong>de</strong> ejecución.<br />
Generalmente existe un gran número <strong>de</strong> planes que implementan al árbol <strong>de</strong> la<br />
consulta; <strong>el</strong> proceso <strong>de</strong> encontrar <strong>el</strong> mejor <strong>de</strong> estos planes se le <strong>de</strong>nomina<br />
optimización <strong>de</strong> <strong>consultas</strong>, entendiéndose que esta optimización viene dada por<br />
una medida <strong>de</strong> rendimiento <strong>para</strong> la ejecución <strong>de</strong> <strong>consultas</strong> (como por ejemplo <strong>el</strong><br />
tiempo <strong>de</strong> ejecución), queremos encontrar entonces la consulta que tenga <strong>el</strong> mejor<br />
rendimiento <strong>de</strong> ejecución. El objetivo es que <strong>el</strong> plan sea <strong>el</strong> óptimo (o <strong>el</strong> más<br />
cercano a) dado <strong>el</strong> espacio <strong>de</strong> búsqueda <strong>de</strong>l optimizador.<br />
50
Finalmente <strong>el</strong> optimizador envía <strong>el</strong> plan óptimo al motor <strong>de</strong> ejecución. El<br />
motor <strong>de</strong> ejecución ejecuta <strong>el</strong> plan usando como entrada las r<strong>el</strong>aciones<br />
almacenadas en las base <strong>de</strong> datos y produce una tabla con los datos solicitados<br />
como salida.<br />
Los primeros optimizadores <strong>de</strong> <strong>consultas</strong> fueron <strong>de</strong>scritos <strong>para</strong> System R<br />
[S<strong>el</strong>inger79] y <strong>para</strong> Ingress [Wong76] en los años 1979 y 1976 respectivamente.<br />
Estos fueron implementados <strong>para</strong> variantes particulares <strong>de</strong>l mo<strong>de</strong>lo R<strong>el</strong>acional y<br />
funcionan lo suficientemente bien en la medida <strong>de</strong> sus implementaciones físicas<br />
<strong>de</strong>l mo<strong>de</strong>lo. El Optimizador <strong>de</strong> System R ha sido la base <strong>de</strong> otros optimizadores <strong>de</strong><br />
bases <strong>de</strong> datos comerciales.<br />
4.2. El optimizador <strong>de</strong> System R.<br />
[S<strong>el</strong>inger79] propone una <strong>de</strong>scomposición <strong>de</strong> 4 fases en <strong>el</strong> procesamiento<br />
<strong>de</strong> una consulta SQL: parsing, optimización, generación <strong>de</strong> código y ejecución. Al<br />
principio cada sentencia SQL es enviada al parser (analizador sintáctico), quien se<br />
encarga <strong>de</strong> chequear la sintaxis <strong>de</strong> la consulta; si no hay errores, <strong>el</strong> parser llama<br />
al optimizador, quien toma todos los nombres <strong>de</strong> tablas y columnas referenciadas<br />
por la consulta y las busca en <strong>el</strong> catalogo <strong>de</strong> la BD <strong>para</strong> verificar su existencia y<br />
rescatar estadísticas y caminos <strong>de</strong> accesos almacenados. Es <strong>el</strong> optimizador quien<br />
también analiza los tipos <strong>de</strong> datos y tamaños <strong>de</strong> cada columna con <strong>el</strong> fin <strong>de</strong> revisar<br />
en la lista SELECT 7 como en <strong>el</strong> Arbol WHERE 8 la existencia <strong>de</strong> errores <strong>de</strong><br />
semántica e incompatibilida<strong>de</strong>s <strong>de</strong> tipos <strong>de</strong> datos.<br />
7 Lista <strong>de</strong> todos los <strong>el</strong>ementos que están en una cláusula s<strong>el</strong>ect.<br />
8<br />
Estructura <strong>de</strong> árbol que contiene todos los predicados contenidos en la clausula<br />
WHERE.<br />
51
Finalmente realiza la s<strong>el</strong>ección <strong>de</strong> los caminos <strong>de</strong> acceso. Si una consulta<br />
tiene más <strong>de</strong> un query block 9 (en a<strong>de</strong>lante bloque) <strong>de</strong>termina <strong>el</strong> or<strong>de</strong>n <strong>de</strong><br />
evaluación <strong>de</strong> estos a lo largo <strong>de</strong> la consulta, luego procesa <strong>para</strong> cada bloque las<br />
r<strong>el</strong>aciones enunciadas en la lista FROM 10 . Si en <strong>el</strong> bloque existe más <strong>de</strong> una<br />
r<strong>el</strong>ación, <strong>el</strong> optimizador realiza permutaciones <strong>de</strong> los métodos <strong>de</strong> join, por tanto, se<br />
<strong>el</strong>ige <strong>el</strong> camino <strong>de</strong> acceso que minimice <strong>el</strong> costo <strong>para</strong> <strong>el</strong> bloque. Esta solución<br />
recibe <strong>el</strong> nombre <strong>de</strong> “plan <strong>de</strong> ejecución” [S<strong>el</strong>inger79] <strong>el</strong> cual se representa en <strong>el</strong><br />
<strong>lenguaje</strong> <strong>de</strong> especificación <strong>de</strong> accesos (ASL) cuya <strong>de</strong>finición queda fuera <strong>de</strong> los<br />
alcances <strong>de</strong> este trabajo. Para mayor Información consultar [Lorie78].<br />
El generador <strong>de</strong> código es un programa que traslada árboles ASL en<br />
<strong>lenguaje</strong> <strong>de</strong> máquina <strong>para</strong> ejecutar <strong>el</strong> plan escogido por <strong>el</strong> optimizador, <strong>para</strong> hacer<br />
esto utiliza un pequeño número <strong>de</strong> plantillas <strong>de</strong> código <strong>para</strong> representar todos los<br />
casos posibles, durante esta fase se reemplaza <strong>el</strong> árbol generado por <strong>el</strong> parser en<br />
código <strong>de</strong> maquina ejecutable y sus estructuras <strong>de</strong> datos asociadas.<br />
4.2.1. RSS (research storage system)<br />
El RSS es <strong>el</strong> subsistema <strong>de</strong> almacenamiento <strong>de</strong> system R, este es <strong>el</strong><br />
responsable <strong>de</strong> mantener <strong>el</strong> almacenamiento físico <strong>de</strong> las r<strong>el</strong>aciones, <strong>de</strong> los<br />
caminos <strong>de</strong> acceso a <strong>el</strong>las, bloqueos (en un ambiente multiusuario), y <strong>de</strong> las<br />
capacida<strong>de</strong>s <strong>de</strong> registro <strong>de</strong> transacciones y recuperación. El RSI (Research<br />
Storage Interface) es la interfaz orientada a la tupla que system R presenta al<br />
usuario final.<br />
9<br />
Un query block es un bloque <strong>de</strong> cláusulas que conforman una consulta sql <strong>de</strong> la forma<br />
SELECT, FROM, WHERE, GROUP BY, ORDER BY.<br />
10 Lista <strong>de</strong> todas las r<strong>el</strong>aciones enunciadas en la clausula FROM <strong>de</strong> una consulta sql.<br />
52
Una R<strong>el</strong>ación se almacena en <strong>el</strong> RSS como una colección <strong>de</strong> tuplas que<br />
cumplen con las siguientes características:<br />
• sus columnas son contiguas,<br />
• se almacenan en páginas <strong>de</strong> 4 Kb,<br />
• una tupla no pue<strong>de</strong> rebasar una página.<br />
Las páginas se organizan en segmentos, los segmentos pue<strong>de</strong>n contener<br />
una o más r<strong>el</strong>aciones pero una r<strong>el</strong>ación no pue<strong>de</strong> rebasar un segmento.<br />
La manera <strong>de</strong> accesar tuplas <strong>de</strong> una r<strong>el</strong>ación es por medio <strong>de</strong> un proceso<br />
llamado RSS scan, este retorna una tupla a la vez a lo largo <strong>de</strong>l camino <strong>de</strong> acceso<br />
indicado. Los comandos principales son: OPEN, NEXT y CLOSE.<br />
Existen 2 tipos <strong>de</strong> recorridos (scan), <strong>el</strong> primero es un segment scan, <strong>el</strong> cual<br />
encuentra todas las tuplas <strong>de</strong> una r<strong>el</strong>ación dada, consiste básicamente <strong>de</strong> una<br />
serie <strong>de</strong> NEXT que recorren todas las páginas <strong>de</strong>l segmento (que pue<strong>de</strong>n<br />
contener tuplas <strong>para</strong> cualquier r<strong>el</strong>ación) y <strong>de</strong> don<strong>de</strong> rescatan aqu<strong>el</strong>las tuplas que<br />
pertenecen a la r<strong>el</strong>ación dada.<br />
El segundo tipo <strong>de</strong> recorrido es un in<strong>de</strong>x scan 11 , los índices se almacenan<br />
en páginas distintas a las páginas <strong>de</strong> datos y son implementados como B-tree<br />
cuyas hojas <strong>de</strong>l árbol son páginas que contienen conjuntos <strong>de</strong> ya sea claves,<br />
i<strong>de</strong>ntificadores, o tuplas que contienen la clave; por lo tanto una serie <strong>de</strong> NEXT<br />
sobre un “in<strong>de</strong>x scan”, realiza una lectura secuencial a lo largo <strong>de</strong> las hojas<br />
obteniendo las tuplas <strong>de</strong> i<strong>de</strong>ntificadores que se igualan a la clave <strong>de</strong> búsqueda o<br />
usándolas <strong>para</strong> encontrar y retornar las tuplas <strong>de</strong> datos en <strong>el</strong> or<strong>de</strong>n <strong>de</strong> las claves<br />
11 un índice pue<strong>de</strong> ser creado por un usuario <strong>de</strong> system R en una o más columnas <strong>de</strong> una<br />
r<strong>el</strong>ación, y una r<strong>el</strong>ación pue<strong>de</strong> cero o más índices asociados a esta.<br />
53
dadas. Las paginas <strong>de</strong> índices están enca<strong>de</strong>nas juntas, por lo tanto las sentencias<br />
NEXT no necesitan referenciar paginas que se encuentren más arriba <strong>de</strong>l índice.<br />
En un “segment scan” todas las páginas no vacías <strong>de</strong> un segmento se<br />
accesan sólo una vez sin importar si tienen o no tuplas que pertenezcan a la<br />
r<strong>el</strong>ación. En un “in<strong>de</strong>x scan” las páginas <strong>de</strong> índices se accesan sólo una vez, sin<br />
embargo las páginas <strong>de</strong> datos se pue<strong>de</strong>n tocar más <strong>de</strong> una vez.<br />
Si las tuplas han sido insertadas en las paginas <strong>de</strong>l segmento en <strong>el</strong> or<strong>de</strong>n<br />
<strong>de</strong>l índice y si este or<strong>de</strong>n se mantiene diremos que <strong>el</strong> índice es un índice en<br />
cluster, este tipo <strong>de</strong> índices tiene la propiedad <strong>de</strong> que a<strong>de</strong>más <strong>de</strong> las paginas <strong>de</strong><br />
índices, también las paginas <strong>de</strong> datos se accesan solamente una vez en un “in<strong>de</strong>x<br />
scan”. Cabe <strong>de</strong>stacar <strong>de</strong> que un “in<strong>de</strong>x scan” no necesita recorrer toda la r<strong>el</strong>ación,<br />
pues pue<strong>de</strong> recibir llaves <strong>de</strong> inicio y fin.<br />
Ambos tipos <strong>de</strong> scan pue<strong>de</strong>n recibir un conjunto <strong>de</strong> predicados llamados<br />
predicados sargables o SARGS (“search arguments”) los cuales tiene la<br />
particularidad <strong>de</strong> que son aplicados a las tuplas antes <strong>de</strong> que sean <strong>de</strong>vu<strong>el</strong>tas al<br />
RSI. Un predicado sargable es uno <strong>de</strong> la forma:<br />
“columna operador_<strong>de</strong>_com<strong>para</strong>ción valor”.<br />
4.2.2. Costos <strong>para</strong> los caminos <strong>de</strong> acceso <strong>de</strong> r<strong>el</strong>aciones simples.<br />
El optimizador <strong>de</strong> System trata <strong>de</strong> manera distinta a las <strong>consultas</strong> que<br />
hacen referencia a una sola tabla (r<strong>el</strong>aciones simples) <strong>de</strong> las que se <strong>de</strong>ben tratar<br />
como un Join. Para <strong>el</strong> primer caso, <strong>el</strong> optimizador examina tanto los predicados <strong>de</strong><br />
la consulta como también los caminos <strong>de</strong> acceso disponibles <strong>para</strong> la r<strong>el</strong>ación<br />
referenciada y evalúa una fórmula <strong>de</strong> costo <strong>para</strong> cada plan <strong>de</strong> acceso usando la<br />
siguiente fórmula:<br />
54
COSTO = Páginas Rescatadas + W * (RSI calls)<br />
Este costo es una medida <strong>de</strong> peso entre las E/S (páginas rescatadas) y la<br />
utilización <strong>de</strong> CPU (instrucciones ejecutadas). W es un factor <strong>de</strong> peso ajustable<br />
entre E/S y la CPU 12 . RSI calls es la estimación <strong>de</strong>l número <strong>de</strong> tuplas a retornar.<br />
Dada esta formula la <strong>el</strong>ección <strong>de</strong>l camino <strong>de</strong> costo mínimo <strong>para</strong> procesar una<br />
consulta tien<strong>de</strong> a minimizar <strong>el</strong> total <strong>de</strong> recursos requeridos.<br />
La ejecución <strong>de</strong> la validación semántica <strong>de</strong>l optimizador examina cada<br />
bloque WHERE (<strong>el</strong> respectivo árbol <strong>de</strong>be estar en la forma normal conjuntiva) con<br />
<strong>el</strong> objetivo <strong>de</strong> i<strong>de</strong>ntificar los factores booleanos.<br />
Se llama factor booleano a cada uno <strong>de</strong> los predicados <strong>de</strong>l Arbol WHERE (o<br />
conjunciones) que ha sido previamente normalizado.<br />
Se dice que un índice calza un factor booleano si <strong>el</strong> factor booleano es un<br />
predicado sargable cuya columna referenciada es la clave <strong>de</strong>l índice.<br />
Se dice que un predicado o un conjunto <strong>de</strong> predicados calza a un camino<br />
<strong>de</strong> acceso por índice cuando los predicados son sargables y las columnas<br />
mencionadas en los predicados son un substring inicial <strong>de</strong>l conjunto <strong>de</strong> columnas<br />
<strong>de</strong> la clave <strong>de</strong>l índice. Si un índice calza un factor booleano entonces un camino<br />
<strong>de</strong> acceso que ocupe este índice será una manera eficiente <strong>de</strong> satisfacer <strong>el</strong> factor<br />
booleano.<br />
12 Una forma <strong>de</strong> calcularlo pue<strong>de</strong> ser tomar los MIPS <strong>de</strong> una <strong>de</strong>terminada CPU y por otro<br />
lado tomar <strong>el</strong> número <strong>de</strong> instrucciones que se utilizan en una llamada RSS. W podría ser <strong>el</strong><br />
producto <strong>de</strong> estos 2 valores medidos durante <strong>el</strong> tiempo transcurrido en una búsqueda típica a<br />
disco. Por lo tanto W tendrá diferentes valores <strong>de</strong>pendiendo <strong>de</strong> distintas configuraciones <strong>de</strong><br />
hardware. (Don Chamberlin, 12/09/2001)<br />
55
Durante la mirada al catálogo, <strong>el</strong> optimizador recupera estadísticas <strong>para</strong> las<br />
r<strong>el</strong>aciones <strong>de</strong> la consulta y caminos <strong>de</strong> acceso disponibles <strong>para</strong> cada r<strong>el</strong>ación. Las<br />
estadísticas son las siguientes:<br />
Para cada r<strong>el</strong>ación T.<br />
• NCARD(T), cardinalidad <strong>de</strong> la r<strong>el</strong>ación T.<br />
• TCARD(T), número <strong>de</strong> páginas <strong>de</strong>l segmento que contienen tuplas<br />
<strong>de</strong> la r<strong>el</strong>ación T.<br />
• P(T), fracción <strong>de</strong> paginas <strong>de</strong> datos que contienen tuplas <strong>de</strong> la<br />
r<strong>el</strong>ación T.<br />
P(T) = TCARD(T)/Número_<strong>de</strong>_páginas_no_vacías_en_<strong>el</strong>_segmento.<br />
Para Cada índice en la r<strong>el</strong>ación T.<br />
• ICARD(I), Número <strong>de</strong> claves distintas en <strong>el</strong> índice I<br />
• NINDEX(I), Número <strong>de</strong> páginas en <strong>el</strong> índice I.<br />
Estas estadísticas son mantenidas por <strong>el</strong> catálogo <strong>de</strong> System R, y<br />
provienen <strong>de</strong> distintas fuentes, son actualizadas periódicamente por <strong>el</strong> comando<br />
UPDATE STATISTICS, <strong>el</strong> cual pue<strong>de</strong> ser ejecutado por cualquier usuario.<br />
Usando estas estadísticas, <strong>el</strong> optimizador asigna un factor <strong>de</strong> s<strong>el</strong>ección “F”<br />
<strong>para</strong> cada factor booleano en la lista <strong>de</strong> predicados. Este factor es la estimación<br />
<strong>de</strong> la cantidad <strong>de</strong> tuplas que satisfacen <strong>el</strong> predicado. Se asume que una falta <strong>de</strong><br />
estadísticas implica la <strong>el</strong>ección <strong>de</strong> un factor arbitrario.<br />
56
La siguiente tabla muestra los factores a utilizar <strong>para</strong> los distintos tipos <strong>de</strong><br />
predicados:<br />
columna = valor<br />
F = 1 / ICARD(índice) si existe un índice <strong>para</strong> la columna. Esto asume<br />
una distribución uniforme <strong>de</strong> los datos a lo largo <strong>de</strong>l dominio <strong>de</strong> la<br />
columna.<br />
F = 1 / 10 en otro caso.<br />
columna1 = columna2<br />
F = 1 / MAX(ICARD(índice_columna1), ICARD(índice_columna2)) si existen<br />
índices tanto en columna1 como en columna2. Esto asume que cada valor<br />
en <strong>el</strong> dominio <strong>de</strong>l índice con menor cardinalidad se iguala a un valor<br />
en <strong>el</strong> otro índice.<br />
F = 1 / ICARD(indice_columna-i) si sólo existe un índice sobre la<br />
columna-i<br />
F = 1 / 10 en otro caso<br />
Columna > valor (o cualquier otra com<strong>para</strong>ción abierta)<br />
F = (mayor_valor_dominio – valor) / (mayor_valor_dominio –<br />
menor_valor_dominio) si la columna es <strong>de</strong> tipo aritmético y <strong>el</strong> valor<br />
es conocido en <strong>el</strong> momento <strong>de</strong> escoger <strong>el</strong> camino <strong>de</strong> acceso.<br />
mayor_valor y menor_valor son los límites <strong>de</strong>l dominio.<br />
F = 1 / 3 en otro caso. Respon<strong>de</strong> a la hipótesis <strong>de</strong> que son menos las<br />
<strong>consultas</strong> que usan predicados que son satisfechos por más <strong>de</strong> la mitad<br />
<strong>de</strong> las tuplas.<br />
Columna between valor1 and valor2<br />
F = (valor2 – valor1) / (mayor_valor_dominio – menor_valor_dominio)<br />
que correspon<strong>de</strong> a una razón entre <strong>el</strong> rango <strong>de</strong> valores <strong>de</strong> la cláusula<br />
57
BETWEEN con respecto al rango <strong>de</strong> valores <strong>de</strong>l dominio siempre que la<br />
columna sea aritmética y ambos valores sean conocidos al momento <strong>de</strong><br />
escoger <strong>el</strong> camino <strong>de</strong> acceso.<br />
F = 1 / 4 en otro caso.<br />
Columna in (lista_<strong>de</strong>_valores)<br />
F = (numero_<strong>de</strong>_<strong>el</strong>ementos_<strong>de</strong>_la_lista) * (factor_<strong>de</strong>_s<strong>el</strong>ección <strong>para</strong><br />
columna = valor) siempre y cuando no sea mayor que ½.<br />
Columna in subconsulta<br />
F = (cardinalidad estimada <strong>de</strong> la subconsulta) / (producto <strong>de</strong> las<br />
cardinalida<strong>de</strong>s<br />
subconsulta)<br />
<strong>de</strong> todas las r<strong>el</strong>aciones <strong>de</strong> la lista FROM <strong>de</strong> la<br />
El cálculo <strong>de</strong> la cardinalidad <strong>de</strong> una subconsulta se explica más<br />
a<strong>de</strong>lante.<br />
Predicado1 OR predicado2<br />
F = F(predicado1) + F(predicado2) – F(predicado1) * F(predicado2)<br />
Predicado1 AND predicado2<br />
F = F(predicado1) * F(predicado2)<br />
NOT predicado<br />
F = 1 – F(predicado)<br />
Tabla 4-1 - Factores <strong>de</strong> S<strong>el</strong>ección <strong>para</strong> caminos <strong>de</strong> acceso a R<strong>el</strong>aciones Simples.<br />
La cardinalidad <strong>de</strong> una consulta (QCARD) es <strong>el</strong> producto <strong>de</strong> las<br />
cardinalida<strong>de</strong>s <strong>de</strong> cada r<strong>el</strong>ación involucrada multiplicado por <strong>el</strong> producto <strong>de</strong> todos<br />
los factores <strong>de</strong> s<strong>el</strong>ección. El número esperado <strong>de</strong> llamadas RSI (RSICARD) es <strong>el</strong><br />
producto <strong>de</strong> las cardinalida<strong>de</strong>s <strong>de</strong> las r<strong>el</strong>aciones por los factores <strong>de</strong> s<strong>el</strong>ección <strong>de</strong><br />
58
todos los factores booleanos sargables (dado que estos argumentos son los que<br />
se aplican antes <strong>de</strong> ser retornadas a la RSI).<br />
El escoger <strong>el</strong> camino <strong>de</strong> acceso óptimo <strong>para</strong> una r<strong>el</strong>ación consiste entonces<br />
en usar estos factores <strong>de</strong> s<strong>el</strong>ección junto con las estadísticas <strong>de</strong>l catalogo en<br />
fórmulas <strong>de</strong>finidas. Para llegar a estas fórmulas se presentara entonces la<br />
siguiente <strong>de</strong>finición.<br />
Se dice que un <strong>de</strong>terminado or<strong>de</strong>n <strong>de</strong> tuplas es un “interesting or<strong>de</strong>r” si este<br />
or<strong>de</strong>n es uno <strong>de</strong> los especificados en las cláusulas GROUP BY u ORDER BY.<br />
Para una r<strong>el</strong>ación simple, la solución óptima se obtiene evaluando <strong>el</strong> costo<br />
<strong>para</strong> cada camino <strong>de</strong> acceso (cada índice en la r<strong>el</strong>ación más un “segment scan”).<br />
Si no hay cláusulas GROUP BY u ORDER BY en la consulta no hay “interesting<br />
or<strong>de</strong>rs”, por lo tanto se <strong>de</strong>berá <strong>el</strong>egir <strong>el</strong> camino <strong>de</strong> acceso más barato. Si estas<br />
sentencias existen, se necesita examinar los caminos <strong>de</strong> acceso más baratos que<br />
produzcan tuplas en cada uno <strong>de</strong> los “insteresting or<strong>de</strong>rs”, luego, <strong>el</strong> costo <strong>de</strong><br />
producir estos or<strong>de</strong>namientos <strong>de</strong>be com<strong>para</strong>rse al costo <strong>de</strong>l más barato <strong>de</strong> los<br />
caminos “sin or<strong>de</strong>n” más <strong>el</strong> costo <strong>de</strong> or<strong>de</strong>nar las QCARDS tuplas <strong>de</strong> la consulta<br />
en <strong>el</strong> or<strong>de</strong>n dado. La más barata <strong>de</strong> estas alternativas será la <strong>el</strong>egida como <strong>el</strong> plan<br />
<strong>de</strong> ejecución <strong>para</strong> <strong>el</strong> bloque.<br />
La siguiente tabla muestra las fórmulas <strong>de</strong> costo <strong>para</strong> caminos <strong>de</strong> acceso a<br />
r<strong>el</strong>aciones simples. Estas fórmulas se calculan basándose en la suma <strong>de</strong>l número<br />
<strong>de</strong> páginas <strong>de</strong> índices y las paginas <strong>de</strong> datos más <strong>el</strong> factor <strong>de</strong> peso multiplicado<br />
por las “RSI call”. En algunos casos se dan varias alternativas <strong>de</strong>pendiendo <strong>de</strong> si<br />
<strong>el</strong> conjunto <strong>de</strong> tuplas rescatadas “cabe” completamente en <strong>el</strong> RSS buffer pool.<br />
Para índices en cluster se asume que una página permanecerá en <strong>el</strong> buffer lo<br />
suficiente como <strong>para</strong> que todas las tuplas puedan ser rescatadas <strong>de</strong> <strong>el</strong>la. Para<br />
índices que no son en cluster y en <strong>el</strong> caso <strong>de</strong> aqu<strong>el</strong>las r<strong>el</strong>aciones que no caben en<br />
59
<strong>el</strong> buffer, se asume que la r<strong>el</strong>ación es suficientemente gran<strong>de</strong> con respecto al<br />
buffer <strong>de</strong> manera que se requiere una lectura <strong>de</strong> página por cada tupla rescatada.<br />
Situación<br />
Indice único que calza con<br />
un predicado <strong>de</strong> igualdad<br />
Indice en cluster I que<br />
calza con uno o más<br />
factores booleanos<br />
Indice I que calza uno o<br />
más factores boléanos<br />
Indice en cluster I que no<br />
calza con ningún factor<br />
booleano<br />
Indice I que no calza con<br />
ningún factor booleano<br />
Costo<br />
1 + 1 + W<br />
F(preds) * (NINDX(I) + TCARD) + W * RSICARD<br />
60<br />
F(preds) * (NINDX(I) + NCARD) + W * RSICARD<br />
o<br />
F(preds) * (NINDX(I) + TCARD) + W * RSICARD<br />
si este número cabe en <strong>el</strong> buffer <strong>de</strong> System R<br />
(NINDX(I) + TCARD) + W * RSICARD<br />
(NINDX(I) + NCARD) + W * RSICARD<br />
o<br />
(NINDX(I) + TCARD) + W * RSICARD si este<br />
número cabe en <strong>el</strong> buffer <strong>de</strong> System R
Segment Scan<br />
TCARD/P + W * RSICARD<br />
Tabla 4-2 - Fórmulas <strong>de</strong> costo <strong>para</strong> caminos <strong>de</strong> acceso a r<strong>el</strong>aciones simples<br />
4.2.3. S<strong>el</strong>ección <strong>de</strong>l camino <strong>de</strong> acceso <strong>para</strong> joins.<br />
El optimizador <strong>de</strong> system R tiene 2 métodos <strong>de</strong> s<strong>el</strong>ección <strong>de</strong> caminos <strong>de</strong><br />
acceso <strong>para</strong> los joins <strong>de</strong> dos r<strong>el</strong>aciones (join <strong>de</strong> or<strong>de</strong>n 2), primero se <strong>de</strong>scribirán<br />
estos métodos y luego se discutirá como <strong>el</strong>los pue<strong>de</strong>n ser extendidos <strong>para</strong> joins<br />
con más <strong>de</strong> 2 r<strong>el</strong>aciones (join <strong>de</strong> or<strong>de</strong>n n). Para <strong>el</strong> primer caso, la r<strong>el</strong>ación base<br />
recibirá <strong>el</strong> nombre <strong>de</strong> r<strong>el</strong>ación outer, la segunda r<strong>el</strong>ación se le llamará inner y<br />
correspon<strong>de</strong>rá a la r<strong>el</strong>ación <strong>de</strong> la cual se sacarán las tuplas <strong>de</strong>pendiendo <strong>de</strong> los<br />
valores obtenidos <strong>de</strong> la r<strong>el</strong>ación outer. Un predicado que r<strong>el</strong>aciona columnas <strong>de</strong> 2<br />
r<strong>el</strong>aciones <strong>de</strong> un join se llamará un predicado <strong>de</strong> join, las columnas referenciadas<br />
en estos predicados se llamaran columnas <strong>de</strong> join.<br />
El primer método se llama nested loops (ciclos anidados) y consiste en<br />
recorrer ambas r<strong>el</strong>aciones en cualquier or<strong>de</strong>n. Primero se abre un scan sobre la<br />
r<strong>el</strong>ación outer y se rescata la primera tupla, <strong>para</strong> cada tupla <strong>de</strong> esta r<strong>el</strong>ación se<br />
abre un “segment scan” en la r<strong>el</strong>ación inner <strong>para</strong> rescatar, una a la vez, las tuplas<br />
que coinci<strong>de</strong>n con <strong>el</strong> predicado <strong>de</strong> join.<br />
El segundo método se llama merging scans (recorrido por mezcla), requiere<br />
que las dos r<strong>el</strong>aciones se recorran en <strong>el</strong> or<strong>de</strong>n <strong>de</strong> las columnas <strong>de</strong> join. Esto<br />
implica que, junto con las columnas mencionadas en las cláusulas ORDER BY y<br />
GROUP BY, las columnas <strong>de</strong> un predicado equi-join (aqu<strong>el</strong>los <strong>de</strong> la forma<br />
tabla1.columna1 = tabla2.columna2) también <strong>de</strong>finen “interesting or<strong>de</strong>rs”.<br />
Si hay más <strong>de</strong> un predicado <strong>de</strong> join, uno <strong>de</strong> <strong>el</strong>los es usado como predicado <strong>de</strong> join<br />
y los restantes son tratados como predicados ordinarios. Este método solamente<br />
61
se aplica a equi-joins, si una o ambas r<strong>el</strong>aciones <strong>de</strong>l join no tienen índices en las<br />
columnas <strong>de</strong> join, estas <strong>de</strong>ben ser or<strong>de</strong>nadas en una lista temporal por las<br />
columnas <strong>de</strong> join.<br />
Este método saca provecho <strong>de</strong>l or<strong>de</strong>namiento <strong>de</strong> las columnas <strong>de</strong> join<br />
evitando recorrer la r<strong>el</strong>ación inner por cada tupla <strong>de</strong> la r<strong>el</strong>ación outer. Esto se hace<br />
sincronizando ambos scans y recordando don<strong>de</strong> se encuentran las tuplas que<br />
satisfacen <strong>el</strong> predicado <strong>de</strong> join. Un mayor ahorro <strong>de</strong> esfuerzos se logra si la<br />
r<strong>el</strong>ación inner está en cluster sobre la columna <strong>de</strong> join (como <strong>de</strong>bería si esta fuese<br />
la salida <strong>de</strong> un sort sobre la columna <strong>de</strong> join). “Clustering” sobre una columna<br />
significa que las tuplas que tienen <strong>el</strong> mismo valor en esta columna están<br />
almacenadas físicamente cerca una <strong>de</strong> la otra <strong>de</strong> manera que <strong>el</strong> acceso a una<br />
página traiga varias tuplas.<br />
Un “join <strong>de</strong> or<strong>de</strong>n n” se pue<strong>de</strong> visualizar como una secuencia <strong>de</strong> joins <strong>de</strong><br />
or<strong>de</strong>n 2. En esta visualización 2 r<strong>el</strong>aciones formarán un join, <strong>el</strong> resultado <strong>de</strong> estos<br />
se cruzara con una tercera r<strong>el</strong>ación <strong>para</strong> formar <strong>el</strong> segundo join y así<br />
sucesivamente. En cada paso es posible i<strong>de</strong>ntificar la r<strong>el</strong>ación outer (la que<br />
generalmente es la composición <strong>de</strong>l paso anterior) y la r<strong>el</strong>ación inner como la<br />
r<strong>el</strong>ación que está siendo agregada al join. Es importante notar que no es necesario<br />
que termine <strong>el</strong> primer join <strong>para</strong> que empiece <strong>el</strong> segundo. Tan pronto como se<br />
tenga una tupla producto <strong>de</strong>l primer join <strong>de</strong> or<strong>de</strong>n 2, esta pue<strong>de</strong> ser cruzada con<br />
tuplas <strong>de</strong> la tercera r<strong>el</strong>ación con <strong>el</strong> fin <strong>de</strong> obtener tuplas que sirven <strong>para</strong> <strong>el</strong> tercer<br />
join y así sucesivamente.<br />
Otro factor a consi<strong>de</strong>rar en un join es <strong>el</strong> or<strong>de</strong>n en que se escogen las<br />
r<strong>el</strong>aciones. Aunque la cardinalidad <strong>de</strong> una consulta <strong>de</strong> n r<strong>el</strong>aciones sea la misma<br />
indiferente <strong>de</strong>l or<strong>de</strong>n <strong>de</strong> <strong>el</strong>ección, <strong>el</strong> costo <strong>de</strong> cruzarlas en distinto or<strong>de</strong>n pue<strong>de</strong> ser<br />
substancialmente diferente. Si un bloque tiene n r<strong>el</strong>aciones en su lista FROM<br />
entonces existe n! (n factorial) formas <strong>de</strong> permutar <strong>el</strong> or<strong>de</strong>n <strong>de</strong> las r<strong>el</strong>aciones (la<br />
62
explicación <strong>de</strong> esto se pue<strong>de</strong> encontrar más a<strong>de</strong>lante, en la sección 5.5). Una vez<br />
que las primeras k r<strong>el</strong>aciones han sido unidas, <strong>el</strong> método <strong>para</strong> cruzar esta<br />
composición con la k+1 ésima r<strong>el</strong>ación es in<strong>de</strong>pendiente <strong>de</strong>l or<strong>de</strong>n en que se<br />
unieron las k anteriores. Usando esta propiedad, una forma eficiente <strong>de</strong> organizar<br />
la búsqueda es encontrar <strong>el</strong> mejor or<strong>de</strong>namiento <strong>para</strong> conjuntos sucesivamente<br />
más gran<strong>de</strong>s.<br />
La heurística que se utiliza <strong>para</strong> reducir <strong>el</strong> número <strong>de</strong> permutaciones es<br />
consi<strong>de</strong>rar sólo los or<strong>de</strong>namientos los cuales tienen predicados <strong>de</strong> join que<br />
r<strong>el</strong>acionan la r<strong>el</strong>ación inner con <strong>el</strong> resto <strong>de</strong> las r<strong>el</strong>aciones que participan en <strong>el</strong> join.<br />
Esta heurística permite que todos los joins que requieran productos cartesianos se<br />
realicen lo más tar<strong>de</strong> posible. Por ejemplo, si T1, T2 y T3 son las 3 r<strong>el</strong>aciones <strong>de</strong><br />
una lista FROM y hay predicados <strong>de</strong> join entre T1 T2, y entre T2 y T3 pero sobre<br />
columnas distintas, entonces las permutaciones siguientes no serán consi<strong>de</strong>radas.<br />
T1 – T3 – T2<br />
T3 – T1 – T2<br />
Para encontrar <strong>el</strong> plan óptimo <strong>para</strong> un join <strong>de</strong> or<strong>de</strong>n n se construye un árbol<br />
<strong>de</strong> posibles soluciones. Una solución consiste en una lista or<strong>de</strong>nada <strong>de</strong> r<strong>el</strong>aciones<br />
a ser unidas, <strong>el</strong> método <strong>de</strong> join y un plan que indique como se accesa cada<br />
r<strong>el</strong>ación. Si una <strong>de</strong> las dos r<strong>el</strong>aciones necesita ser or<strong>de</strong>nada antes <strong>de</strong>l join,<br />
entonces se guarda <strong>el</strong> costo <strong>de</strong> este or<strong>de</strong>namiento en <strong>el</strong> plan. Para minimizar la<br />
cantidad <strong>de</strong> “interesting or<strong>de</strong>rs” y con esto también <strong>el</strong> número <strong>de</strong> soluciones, se<br />
calcularán clases <strong>de</strong> equivalencia <strong>para</strong> los “interesting or<strong>de</strong>rs”, y sólo la mejor<br />
solución <strong>de</strong> cada una <strong>de</strong> las clases <strong>de</strong> equivalencia será guardada en <strong>el</strong> árbol.<br />
El árbol <strong>de</strong> búsqueda se construye por medio <strong>de</strong> la iteración <strong>de</strong> las<br />
r<strong>el</strong>aciones que han sido juntadas hasta <strong>el</strong> momento. Primero, se encuentra la<br />
mejor manera <strong>de</strong> accesar a cada r<strong>el</strong>ación simple <strong>para</strong> cada “interesting or<strong>de</strong>r” y<br />
63
<strong>para</strong> <strong>el</strong> caso sin or<strong>de</strong>n. Luego <strong>para</strong> cada una <strong>de</strong> las r<strong>el</strong>aciones se <strong>el</strong>ige la mejor<br />
manera <strong>de</strong> juntar otra r<strong>el</strong>ación a esta (sujeta a las heurísticas <strong>para</strong> <strong>el</strong><br />
or<strong>de</strong>namiento <strong>de</strong> join), esto produce soluciones <strong>para</strong> juntar pares <strong>de</strong> r<strong>el</strong>aciones.<br />
Luego se <strong>el</strong>ige la mejor manera <strong>de</strong> juntar conjuntos <strong>de</strong> 3 r<strong>el</strong>aciones, consi<strong>de</strong>rando<br />
todos los conjuntos <strong>de</strong> 2 r<strong>el</strong>aciones y agregándole una tercera r<strong>el</strong>ación<br />
consi<strong>de</strong>rando las heurísticas <strong>para</strong> <strong>el</strong> or<strong>de</strong>namiento <strong>de</strong> joins. Para cada plan que<br />
juntará un conjunto <strong>de</strong> r<strong>el</strong>aciones se guarda en <strong>el</strong> árbol <strong>el</strong> or<strong>de</strong>n <strong>de</strong> la<br />
composición. Esto ayuda a la consi<strong>de</strong>ración <strong>de</strong> usar un “merge join” que<br />
eventualmente no requiera or<strong>de</strong>namiento adicional <strong>de</strong> tuplas. Luego <strong>de</strong> que se<br />
tienen todas las posibles soluciones, <strong>el</strong> optimizador <strong>el</strong>ige la solución más barata<br />
que da <strong>el</strong> or<strong>de</strong>n requerido (si se ha especificado algún or<strong>de</strong>n). Nótese que si existe<br />
una solución con <strong>el</strong> or<strong>de</strong>n correcto, no se necesitará efectuar un sort <strong>para</strong><br />
satisfacer las cláusulas ORDER BY o GROUP BY, a menos que la solución<br />
or<strong>de</strong>nada sea más costosa que la más barata <strong>de</strong> las sin or<strong>de</strong>n más <strong>el</strong> costo <strong>de</strong><br />
or<strong>de</strong>narlas en <strong>el</strong> or<strong>de</strong>n requerido.<br />
4.2.4. Cálculo <strong>de</strong> costos <strong>para</strong> joins.<br />
El costo <strong>para</strong> un join se calcula dado <strong>el</strong> costo <strong>de</strong> los scans en cada una <strong>de</strong><br />
las r<strong>el</strong>aciones que participan y las respectivas cardinalida<strong>de</strong>s. El costo <strong>de</strong> un scan<br />
en las r<strong>el</strong>aciones participantes se calcula con la fórmula <strong>de</strong> costo <strong>de</strong> r<strong>el</strong>aciones<br />
simples expuestas en <strong>el</strong> punto 4.2.2.<br />
Sea C-outer(path1) <strong>el</strong> costo <strong>de</strong> recorrer la r<strong>el</strong>ación outer vía path1. Sea N la<br />
cardinalidad <strong>de</strong> tuplas que satisfacen los predicados <strong>de</strong> la r<strong>el</strong>ación outer. N se<br />
calcula como:<br />
N = (producto <strong>de</strong> las cardinalida<strong>de</strong>s <strong>de</strong> todas las r<strong>el</strong>aciones T incluidas<br />
hasta <strong>el</strong> momento).<br />
64
Sea C-inner(path2) <strong>el</strong> costo <strong>de</strong> recorrer la r<strong>el</strong>ación inner aplicando todos los<br />
predicados aplicables. Sea <strong>el</strong> costo <strong>de</strong> un “join nested loop”:<br />
c-nested-loop-join(path1, path2) = C-outer(path1) + N * C-inner(path2)<br />
El costo <strong>de</strong> un merge join se pue<strong>de</strong> se<strong>para</strong>r en <strong>el</strong> costo <strong>de</strong> hacer <strong>el</strong> join más<br />
<strong>el</strong> costo <strong>de</strong>l or<strong>de</strong>namiento en cada una <strong>de</strong> las r<strong>el</strong>aciones si fuese necesario. El<br />
costo <strong>de</strong> efectuar <strong>el</strong> merge join es:<br />
c-merge-join(path1, path2) = C-outer(path1) + N * C-inner(path2)<br />
Para <strong>el</strong> caso en que la r<strong>el</strong>ación inner es or<strong>de</strong>nada en una r<strong>el</strong>ación temporal<br />
no se aplica ninguna <strong>de</strong> las fórmulas dadas <strong>para</strong> caminos <strong>de</strong> acceso a r<strong>el</strong>aciones<br />
simples. En este caso <strong>el</strong> inner scan es como un “segment scan” a excepción <strong>de</strong><br />
que <strong>el</strong> método <strong>de</strong> “merging scan” hace uso <strong>de</strong>l hecho <strong>de</strong> que la r<strong>el</strong>ación inner está<br />
or<strong>de</strong>nada, por lo tanto no es necesario realizar un scan a toda la r<strong>el</strong>ación<br />
buscando una coinci<strong>de</strong>ncia. Para este caso se utilizará la siguiente formula <strong>para</strong> <strong>el</strong><br />
costo <strong>de</strong> un “inner scan”:<br />
C-inner(sorted list) = TEMPPAGES / N + W * RSICARD<br />
Don<strong>de</strong> TEMPAGES es <strong>el</strong> número <strong>de</strong> paginas que se requieren <strong>para</strong><br />
mantener la r<strong>el</strong>ación inner. Esta formula asume que durante <strong>el</strong> “merge scan” cada<br />
página <strong>de</strong> la r<strong>el</strong>ación inner se rescata una vez.<br />
Es interesante observar que las formulas <strong>de</strong> costo <strong>para</strong> <strong>el</strong> “nested-loop-join”<br />
y “merge-join” son esencialmente las mismas, la razón <strong>de</strong> porque algunas veces <strong>el</strong><br />
“merge-join” pue<strong>de</strong> ser más eficiente es que <strong>el</strong> costo <strong>de</strong>l inner scan pue<strong>de</strong> ser<br />
mucho más bajo. Una vez or<strong>de</strong>nada, la r<strong>el</strong>ación inner está en cluster sobre la<br />
65
columna <strong>de</strong> join lo que minimiza <strong>el</strong> número <strong>de</strong> paginas rescatadas y, por lo tanto,<br />
no es necesario hacer un scan sobre toda la r<strong>el</strong>ación con fin <strong>el</strong> <strong>de</strong> obtener una<br />
coinci<strong>de</strong>ncia.<br />
4.2.5. Costos <strong>de</strong> <strong>consultas</strong> anidadas.<br />
Una consulta pue<strong>de</strong> aparecer como operando <strong>de</strong> un predicado <strong>de</strong> la forma<br />
“expresión operando consulta”, tal consulta es llamada consulta anidada o<br />
subconsulta. Si <strong>el</strong> operador es uno <strong>de</strong> los cinco operadores escalares ( =, >, >=,
<strong>consultas</strong> son llamadas sub<strong>consultas</strong> corr<strong>el</strong>acionadas. Una consulta<br />
corr<strong>el</strong>acionada <strong>de</strong>be, en principio ser re-evaluada <strong>para</strong> cada tupla candidata <strong>de</strong>l<br />
bloque referenciado. Esta re-evaluación <strong>de</strong>be ser hecha antes <strong>de</strong> que <strong>el</strong> predicado<br />
padre <strong>de</strong> la consulta corr<strong>el</strong>acionada pueda ser testeado <strong>para</strong> aceptación o rechazo<br />
<strong>de</strong> la tupla candidata. Como ejemplo considérese la siguiente consulta:<br />
SELECT NAME<br />
FROM EMPLOYEE X<br />
WHERE SALARY > (SELECT SALARY<br />
FROM EMPLOYEE<br />
WHERE EMPLOYEE_NUMBER = X.MANAGER)<br />
Esta consulta s<strong>el</strong>ecciona los nombres <strong>de</strong> empleados que ganan más que<br />
sus Jefes. Aquí X i<strong>de</strong>ntifica <strong>el</strong> bloque y la r<strong>el</strong>ación que proporciona tuplas<br />
candidatas <strong>para</strong> la corr<strong>el</strong>ación. Para cada tupla candidata <strong>de</strong> la consulta <strong>de</strong> primer<br />
niv<strong>el</strong>, se utilizará <strong>el</strong> valor <strong>de</strong> MANAGER <strong>para</strong> la evaluación <strong>de</strong> la subconsulta, <strong>el</strong><br />
valor <strong>de</strong> la subconsulta se le retorna al predicado “SALARY >” con <strong>el</strong> fin <strong>de</strong> aceptar<br />
o rechazar la tupla candidata.<br />
Si una subconsulta <strong>de</strong> corr<strong>el</strong>ación no está directamente <strong>de</strong>bajo <strong>de</strong>l bloque<br />
que referencia, sino que está se<strong>para</strong>da por medio <strong>de</strong> uno o más bloques, entonces<br />
la evaluación <strong>de</strong> la subconsulta <strong>de</strong> corr<strong>el</strong>ación <strong>de</strong>be ser hecha antes <strong>de</strong> la<br />
evaluación <strong>de</strong>l más alto <strong>de</strong> los bloques intermedios.<br />
Por ejemplo:<br />
67
Niv<strong>el</strong> 1 SELECT NAME<br />
FROM EMPLOYEE X<br />
WHERE SALARY > (<br />
Niv<strong>el</strong> 2 SELECT SALARY<br />
FROM EMPLOYEE<br />
WHERE EMPLOYEE_NUMBER = (<br />
Niv<strong>el</strong> 3 SELECT MANAGER<br />
FROM EMPLOYEE<br />
WHERE EMPLOYEE_NUMBER = X.MANAGER))<br />
Esta consulta s<strong>el</strong>ecciona los nombres <strong>de</strong> los empleados que ganan más<br />
que los Jefes <strong>de</strong> sus Jefes. Como antes se vio, <strong>para</strong> cada tupla candidata <strong>de</strong>l<br />
bloque <strong>de</strong> niv<strong>el</strong> 1 <strong>el</strong> valor <strong>de</strong> EMPLOYEE.MANAGER se usará <strong>para</strong> la evaluación<br />
<strong>de</strong>l bloque <strong>de</strong> niv<strong>el</strong> 3. En este caso, dado que la subconsulta <strong>de</strong> niv<strong>el</strong> 3 referencia<br />
a una valor <strong>de</strong> niv<strong>el</strong> 1 pero no referencia a valores <strong>de</strong> niv<strong>el</strong> 2, esta es evaluada<br />
una vez <strong>para</strong> cada tupla candidata <strong>de</strong> niv<strong>el</strong> 1 pero no <strong>para</strong> las tuplas candidatas <strong>de</strong><br />
niv<strong>el</strong> 2.<br />
Si <strong>el</strong> valor referenciado por la subconsulta <strong>de</strong> corr<strong>el</strong>ación no es único en <strong>el</strong><br />
conjunto <strong>de</strong> tuplas candidatas entonces este procedimiento causará que la<br />
consulta sea re-evaluada <strong>para</strong> cada ocurrencia <strong>de</strong> los valores repetidos. Sin<br />
embargo si la r<strong>el</strong>ación a la que se hace referencia está or<strong>de</strong>nada por la columna<br />
referenciada la re-evaluación pue<strong>de</strong> ser condicional, y <strong>de</strong>pen<strong>de</strong>rá <strong>de</strong> saber si <strong>el</strong><br />
valor actual es <strong>el</strong> mismo que <strong>el</strong> <strong>de</strong> la tupla candidata procesada anteriormente. Si<br />
son iguales entonces se pue<strong>de</strong> utilizar la evaluación anterior, en algunos casos<br />
incluso se pue<strong>de</strong> or<strong>de</strong>nar la r<strong>el</strong>ación por la columna referenciada con <strong>el</strong> fin <strong>de</strong><br />
evitar la innecesaria re-evaluación <strong>de</strong> sub<strong>consultas</strong>. Con <strong>el</strong> fin <strong>de</strong> <strong>de</strong>terminar si los<br />
valores <strong>de</strong> una columna referenciada son únicos se pue<strong>de</strong>n utilizar pistas como<br />
NCARD > ICARD, don<strong>de</strong> NCARD es la cardinalidad <strong>de</strong> la r<strong>el</strong>ación y ICARD es la<br />
cardinalidad <strong>de</strong>l índice sobre la columna referenciada.<br />
68
Capítulo 5. Optimización <strong>de</strong> <strong>consultas</strong>, Fundamento<br />
teórico.<br />
5.1. Introducción.<br />
En Los mo<strong>de</strong>los <strong>de</strong> Red y Jerárquico la optimización <strong>de</strong> <strong>consultas</strong> es tarea<br />
propia <strong>de</strong>l programador <strong>de</strong> aplicaciones, puesto que las instrucciones <strong>de</strong><br />
manipulación <strong>de</strong> datos son propietarias <strong>de</strong>l <strong>lenguaje</strong> anfitrión. Por <strong>el</strong> contrario las<br />
<strong>consultas</strong> <strong>de</strong> base <strong>de</strong> datos r<strong>el</strong>acionales son o bien <strong>de</strong>clarativas o algebraicas. Los<br />
<strong>lenguaje</strong>s algebraicos permiten la transformación algebraica <strong>de</strong> la consulta, luego,<br />
basándose en la especificación algebraica <strong>de</strong> la consulta es r<strong>el</strong>ativamente fácil<br />
<strong>para</strong> <strong>el</strong> optimizador generar diversos planes equivalentes <strong>para</strong> la consulta y <strong>el</strong>egir<br />
<strong>el</strong> menos costoso.<br />
Dado este niv<strong>el</strong> <strong>de</strong> generalidad, <strong>el</strong> optimizador pue<strong>de</strong> ser visto como <strong>el</strong><br />
generador <strong>de</strong> código <strong>de</strong> un compilador <strong>para</strong> <strong>el</strong> <strong>lenguaje</strong> SQL, que produce <strong>el</strong><br />
código que será interpretado por <strong>el</strong> motor <strong>de</strong> ejecución <strong>de</strong> <strong>consultas</strong>, excepto que<br />
<strong>el</strong> optimizador marca énfasis en la capacidad <strong>de</strong> producir <strong>el</strong> código más eficiente,<br />
haciendo uso <strong>para</strong> tales efectos <strong>de</strong>l catálogo <strong>de</strong> la base <strong>de</strong> datos, <strong>de</strong> don<strong>de</strong><br />
obtiene información estadística <strong>de</strong> las r<strong>el</strong>aciones referenciadas por la consulta,<br />
algo que los <strong>lenguaje</strong>s <strong>de</strong> programación tradicionales no hacen.<br />
Un aspecto <strong>de</strong> la optimización <strong>de</strong> <strong>consultas</strong> se sitúa en <strong>el</strong> niv<strong>el</strong> <strong>de</strong>l álgebra<br />
r<strong>el</strong>acional. Dado un conjunto <strong>de</strong> reglas se trata <strong>de</strong> encontrar una expresión que<br />
sea equivalente a la expresión dada pero que sea más eficiente en la ejecución.<br />
69
Con <strong>el</strong> fin <strong>de</strong> s<strong>el</strong>eccionar la mejor estrategia <strong>para</strong> la recuperación <strong>de</strong> datos<br />
<strong>el</strong> optimizador “estima” un costo que estará r<strong>el</strong>acionado a cada plan <strong>de</strong> ejecución.<br />
Este costo está <strong>de</strong>terminado por fórmulas pre<strong>de</strong>finidas en base a información que<br />
se posee <strong>de</strong> la tabla y que se ha rescatado previamente <strong>de</strong>l catálogo <strong>de</strong> la base <strong>de</strong><br />
datos, en realidad <strong>el</strong> optimizador no siempre escoge <strong>el</strong> plan más óptimo, ya que<br />
encontrar la estrategia óptima pue<strong>de</strong> consumir mucho tiempo, por lo tanto se dice<br />
que <strong>el</strong> optimizador “sólo escoge una estrategia razonablemente eficiente”. La<br />
manera con la que <strong>el</strong> optimizador utiliza esa información, las distintas técnicas y<br />
algoritmos que aplica y las transformaciones algebraicas que se realizan son las<br />
que diferencian a los optimizadores <strong>de</strong> bases <strong>de</strong> datos.<br />
Un optimizador basado en <strong>el</strong> costo genera una serie <strong>de</strong> planes <strong>de</strong><br />
evaluación <strong>para</strong> una consulta y luego <strong>el</strong>ige <strong>el</strong> que tiene un menor costo asociado,<br />
las medidas <strong>de</strong> costo comúnmente tienen que ver con la E/S y <strong>el</strong> tiempo <strong>de</strong> CPU<br />
utilizado en ejecutar la consulta, sin embargo, es cuestión <strong>de</strong> cada SGBD <strong>el</strong> <strong>el</strong>egir<br />
las medidas <strong>de</strong> costo que mejor representen <strong>el</strong> criterio <strong>de</strong> minimización en la<br />
utilización <strong>de</strong> recursos.<br />
5.2. Información <strong>de</strong>l catálogo.<br />
Como se ha mencionado anteriormente, la información <strong>de</strong>l catálogo <strong>de</strong> la<br />
base <strong>de</strong> datos le sirve al SGBD <strong>para</strong> estimar <strong>el</strong> costo <strong>de</strong> los planes <strong>de</strong> ejecución<br />
<strong>de</strong> una consulta. La precisión <strong>de</strong> esta información esta ligada directamente a la<br />
periodicidad con la que se actualizan las estadísticas <strong>de</strong>l catálogo. En un caso<br />
i<strong>de</strong>al, cada vez que se compromete una transacción <strong>de</strong> base <strong>de</strong> datos se <strong>de</strong>berían<br />
actualizar las estadísticas <strong>de</strong>l sistema, sin embargo, esto no es posible en un<br />
70
entorno OLTP 13 dada la sobrecarga que estas operaciones le dan al sistema<br />
(básicamente bloqueos en las tablas <strong>de</strong>l catálogo). La solución está entonces en la<br />
posibilidad <strong>de</strong> actualizar estas estadísticas en periodo <strong>de</strong> poca carga <strong>de</strong>l sistema,<br />
algunos SGBD tienen técnicas <strong>de</strong> optimización automáticas <strong>de</strong> las estadísticas<br />
(como es <strong>el</strong> caso <strong>de</strong> MS-SQLServer [Bj<strong>el</strong>etich99]) pero en general se recomienda<br />
que esta tarea la ejecute <strong>el</strong> DBA con la periodicidad que le dicte la experiencia. En<br />
todo caso, la información será más precisa cuanto más bajo sea <strong>el</strong> niv<strong>el</strong> <strong>de</strong><br />
actualizaciones en <strong>el</strong> intervalo <strong>de</strong> tiempo entre actualizaciones <strong>de</strong> Estadísticas.<br />
Cada SGBD tiene distinta información que guardar en <strong>el</strong> catálogo y por<br />
en<strong>de</strong>, <strong>el</strong> catálogo <strong>de</strong> la base <strong>de</strong> datos es distinto entre cada uno <strong>de</strong> estos motores,<br />
sin embargo, hay información que todo optimizador <strong>de</strong>be guardar:<br />
n r Número <strong>de</strong> tuplas <strong>de</strong> la r<strong>el</strong>ación r<br />
b r Número <strong>de</strong> bloques que contienen tuplas <strong>de</strong> la r<strong>el</strong>ación r<br />
t r Tamaño en bytes <strong>de</strong> una tupla <strong>de</strong> r<br />
f r Factor <strong>de</strong> bloqueo <strong>de</strong> r. Número <strong>de</strong> tuplas <strong>de</strong> r que caben en un bloque.<br />
V ( A,<br />
r)<br />
Número <strong>de</strong> valores distintos <strong>de</strong>l atributo A <strong>de</strong> la r<strong>el</strong>ación r<br />
CS ( A,<br />
r)<br />
Número medio <strong>de</strong> tuplas <strong>de</strong> r que satisfacen una condición <strong>de</strong> igualdad<br />
sobre <strong>el</strong> atributo A <strong>de</strong> la r<strong>el</strong>ación r<br />
CS ( A,<br />
r)<br />
= 1 Si A es clave <strong>de</strong> r<br />
nr<br />
CS(<br />
A,<br />
r)<br />
=<br />
V ( A,<br />
r)<br />
Si A no es clave <strong>de</strong> r, se asume una distribución<br />
71<br />
uniforme <strong>de</strong> los datos <strong>de</strong> A sobre r<br />
Tabla 5-1 - Información <strong>de</strong>l Catálogo <strong>para</strong> r<strong>el</strong>aciones simples.<br />
13 On Line Transaction Processing: tipo <strong>de</strong> procesamiento en <strong>el</strong> cual <strong>el</strong> computador<br />
respon<strong>de</strong> los requerimientos <strong>de</strong> usuario inmediatamente, cada requerimiento es consi<strong>de</strong>rado una<br />
transacción. Un ejemplo <strong>de</strong> este tipo <strong>de</strong> procesamiento es <strong>el</strong> <strong>de</strong> los cajeros automáticos.
Por ejemplo, si n r = 10 y V(sexo,r) = 2 entonces CS(sexo,r) = 10 / 2 = 5, se<br />
asume por lo tanto que <strong>el</strong> atributo sexo se distribuye homogéneamente sobre r.<br />
n r ⎡n<br />
⎤ r<br />
Se asume a<strong>de</strong>más que si = f r entonces b r = ⎢ ⎥<br />
br<br />
⎢ f r ⎥<br />
A<strong>de</strong>más <strong>de</strong> la información <strong>de</strong>l catálogo <strong>para</strong> las r<strong>el</strong>aciones, se utiliza<br />
información acerca <strong>de</strong> los índices:<br />
g Grado <strong>de</strong> salida <strong>de</strong> los nodos internos <strong>de</strong>l índice i (<strong>para</strong> índices con<br />
i<br />
estructura <strong>de</strong> Arbol B+)<br />
AA i<br />
Altura <strong>de</strong>l índice <strong>para</strong> <strong>el</strong> atributo A <strong>de</strong> r.<br />
AAi =<br />
i<br />
⎡log f ( V ( A,<br />
r))<br />
⎤<br />
MB Número <strong>de</strong> bloques que ocupa <strong>el</strong> niv<strong>el</strong> más bajo (niv<strong>el</strong> <strong>de</strong> hojas) <strong>de</strong>l índice i<br />
i<br />
5.3. Medidas <strong>de</strong> costo.<br />
Tabla 5-2 - Información <strong>de</strong>l catálogo <strong>para</strong> índices <strong>de</strong> R<strong>el</strong>aciones.<br />
El costo <strong>de</strong> un plan <strong>de</strong> ejecución se pue<strong>de</strong> expresar en términos <strong>de</strong> distintos<br />
recursos <strong>de</strong> hardware, por ejemplo, en <strong>el</strong> caso <strong>de</strong> system R se hace en función <strong>de</strong><br />
la cantidad <strong>de</strong> CPU utilizada y <strong>de</strong> la cantidad <strong>de</strong> páginas <strong>de</strong> disco rescatadas. En<br />
los SGBD distribuidos se agrega a las medidas <strong>el</strong> costo <strong>de</strong> la comunicación <strong>de</strong><br />
re<strong>de</strong>s. En los sistemas que no son centralizados conviene creer que una buena<br />
medida <strong>de</strong>l costo <strong>de</strong> utilización <strong>de</strong> recursos es la que está dada por la<br />
transferencia <strong>de</strong> datos <strong>de</strong>s<strong>de</strong> <strong>el</strong> disco a la memoria. Para simplificar los cálculos<br />
<strong>de</strong> costo se asume que toda operación que recupere datos <strong>de</strong> disco tiene <strong>el</strong><br />
mismo costo, obviando, por simplicidad, los tiempos involucrados en latencia<br />
rotacional y <strong>el</strong> tiempo <strong>de</strong> búsqueda (ver apéndice C apartado C.1.1) .<br />
72
El costo <strong>de</strong> todos los algoritmos <strong>de</strong> optimización <strong>de</strong>pen<strong>de</strong> en gran manera<br />
<strong>de</strong>l tamaño <strong>de</strong> la memoria intermedia (caché) que tenga la memoria principal. En<br />
<strong>el</strong> mejor <strong>de</strong> los casos todos los datos requeridos se encuentran en la memoria<br />
principal por lo que no se hace necesario acce<strong>de</strong>r al disco.<br />
Al igual que en <strong>el</strong> caso <strong>de</strong>l optimizador <strong>de</strong> system R, este trabajo presenta<br />
los algoritmos <strong>de</strong> optimización consi<strong>de</strong>rando <strong>el</strong> peor caso, en <strong>el</strong> cual sólo algunos<br />
datos caben en la memoria principal, más bien dicho, sólo un bloque por r<strong>el</strong>ación.<br />
5.3.1. Caminos <strong>de</strong> acceso a s<strong>el</strong>ecciones simples.<br />
5.3.1.1. Exploraciones sin índices.<br />
Los siguientes algoritmos implementan la operación <strong>de</strong> s<strong>el</strong>ección sobre una<br />
r<strong>el</strong>ación cuyas tuplas están almacenadas <strong>de</strong> manera contigua en un archivo 14 .<br />
A1. Búsqueda lineal (Full scan o table scan): Se examina cada bloque <strong>de</strong>l<br />
archivo y se comprueba si los registros cumplen con la condición <strong>de</strong> s<strong>el</strong>ección. El<br />
costo estimado <strong>de</strong> este algoritmo es :<br />
C = b<br />
A2. Búsqueda binaria: Si la tabla esta or<strong>de</strong>nada físicamente por <strong>el</strong> atributo A y la<br />
condición <strong>de</strong> s<strong>el</strong>ección es una igualdad sobre <strong>el</strong> atributo entonces se pue<strong>de</strong> utilizar<br />
búsqueda binaria [Kruse84].<br />
14 Se enten<strong>de</strong>rá como archivo al medio <strong>de</strong> almacenamiento físico en disco ya sea por<br />
medio <strong>de</strong> sistemas <strong>de</strong> archivos o como <strong>de</strong>vice <strong>de</strong> datos (raw <strong>de</strong>vices) <strong>de</strong>pendiendo <strong>de</strong> las<br />
características <strong>de</strong>l motor <strong>de</strong> base <strong>de</strong> datos y <strong>de</strong>l sistema operativo que lo soporta.<br />
A1<br />
r<br />
73
⎡CS(<br />
A,<br />
r)<br />
⎤<br />
⎢ ⎥<br />
⎢ f r ⎥<br />
El costo estimado será : = ⎡ ( ) ⎤+ −1<br />
Basado en la suposición <strong>de</strong> que los bloques <strong>de</strong> la r<strong>el</strong>ación se almacenan <strong>de</strong><br />
manera contigua en <strong>el</strong> disco, don<strong>de</strong> ⎡log 2 ( r ) ⎤<br />
C<br />
A2<br />
log 2<br />
b<br />
r<br />
74<br />
b es <strong>el</strong> costo <strong>de</strong> localizar la primera<br />
⎡CS(<br />
A,<br />
r)<br />
⎤<br />
tupla por medio <strong>de</strong> búsqueda binaria, y ⎢ ⎥ −1<br />
es <strong>el</strong> número <strong>de</strong> bloques que<br />
⎢ f r ⎥<br />
cumplen la condición <strong>de</strong> igualdad sobre <strong>el</strong> atributo A menos <strong>el</strong> bloque que se ha<br />
rescatado con la búsqueda binaria.<br />
5.3.1.2. Exploraciones con índices.<br />
Se <strong>de</strong>nomina “camino <strong>de</strong> acceso” (access path) a cada una <strong>de</strong> las formas<br />
<strong>de</strong> acce<strong>de</strong>r a los registros <strong>de</strong> una tabla por medio <strong>de</strong> la utilización <strong>de</strong> índices. Se<br />
entien<strong>de</strong> como índice primario al índice que permite recorrer los registros <strong>de</strong> una<br />
tabla en un or<strong>de</strong>n que coinci<strong>de</strong> con <strong>el</strong> or<strong>de</strong>n físico <strong>de</strong> la tabla, un índice que no es<br />
primario se <strong>de</strong>nomina índice secundario. En sybase, un índice en cluster siempre<br />
recibe <strong>el</strong> número 1 <strong>de</strong>ntro <strong>de</strong>l conjunto <strong>de</strong> índices que pertenecen a una tabla en<br />
estrecha r<strong>el</strong>ación con la <strong>de</strong>finición <strong>de</strong> índice primario.<br />
Los algoritmos <strong>de</strong> búsqueda que utilizan un índice reciben <strong>el</strong> nombre <strong>de</strong><br />
“exploraciones <strong>de</strong> índice” o “in<strong>de</strong>x scan”. Aunque los índices aseguran la mayor<br />
v<strong>el</strong>ocidad <strong>de</strong> acceso a los datos, su utilización implica <strong>el</strong> acceso a los bloques<br />
propios <strong>de</strong>l índice, lo que se pue<strong>de</strong> consi<strong>de</strong>rar como un gasto adicional y <strong>el</strong> cual<br />
<strong>de</strong>be ser tomado en cuenta en la <strong>el</strong>aboración <strong>de</strong> algoritmos <strong>de</strong> acceso a los datos.<br />
Los siguientes algoritmos son los algoritmos <strong>de</strong> acceso a datos por medio<br />
<strong>de</strong> índices, ya sea primarios o secundarios.
A3. (índice primario, igualdad en la clave): Dado que <strong>el</strong> índice está construido<br />
sobre <strong>el</strong> (los) atributos claves, la búsqueda pue<strong>de</strong> utilizar este índice <strong>para</strong> rescatar<br />
los datos. Por lo tanto <strong>para</strong> recuperar <strong>el</strong> único registro que cumple con la condición<br />
se necesita leer sólo un bloque.<br />
El costo estimado será:<br />
C<br />
A3<br />
= AAi<br />
+ 1<br />
A4. (índice primario, igualdad basada en un atributo no clave): El costo está<br />
<strong>de</strong>terminado por la cantidad <strong>de</strong> bloques que contienen registros que cumplen con<br />
la condición <strong>de</strong> igualdad más la altura <strong>de</strong>l índice.<br />
Ejemplo: supóngase que<br />
n viaje = 36000,<br />
b viaje = 2391,<br />
t viaje = 136,<br />
f viaje = 15,<br />
⎡CS(<br />
A,<br />
r)<br />
⎤<br />
El costo estimado será: C A4<br />
= ⎢ ⎥ + AAi<br />
⎢ fr<br />
⎥<br />
que existe un índice B+ primario <strong>para</strong> las columnas PATENTE+CORRELATIVO.<br />
Se <strong>de</strong>sea s<strong>el</strong>eccionar todos las tuplas <strong>de</strong> la tabla viajes que tengan como patente<br />
= ‘HL-8483’.<br />
Como V(PATENTE,VIAJES) =30, se estima que 36000/30=1200 tuplas <strong>de</strong> la<br />
r<strong>el</strong>ación viajes sean <strong>de</strong>l móvil con patente ‘HL-8483’. Se pue<strong>de</strong> utilizar <strong>el</strong> índice<br />
primario <strong>para</strong> leer los 1200/15=80 bloques que cumplen con la condición.<br />
75
Ahora bien, supongamos que <strong>el</strong> índice tiene un tamaño <strong>de</strong>l puntero a disco<br />
<strong>de</strong> 8 bytes, sabiendo que <strong>el</strong> tamaño <strong>de</strong> la clave <strong>de</strong>l índice es <strong>de</strong> 12 bytes es lógico<br />
pensar que <strong>para</strong> un bloque <strong>de</strong> 2 Kb. El número <strong>de</strong> claves por bloque <strong>de</strong> índice es<br />
aproximadamente 100. Entonces, una búsqueda por <strong>el</strong> índice necesitará a lo sumo<br />
⎡log50 ( 36000)<br />
⎤<br />
= 3 accesos a bloques <strong>de</strong> disco, por lo tanto <strong>el</strong> número total <strong>de</strong><br />
bloques a disco a leer es <strong>de</strong> 83 (Una explicación acerca <strong>de</strong> los cálculos realizados<br />
<strong>para</strong> la estimación <strong>de</strong> accesos a bloques se pue<strong>de</strong> encontrar en <strong>el</strong> apéndice B).<br />
A5. (Índice secundario, igualdad): Si <strong>el</strong> campo in<strong>de</strong>xado no es clave se asume<br />
que se rescatará CS(A,r) registros, como <strong>el</strong> índice es secundario se estudia <strong>el</strong> peor<br />
caso, <strong>el</strong> cual propone que cada uno <strong>de</strong> los registros se encuentra en un bloque<br />
diferente, por lo tanto <strong>el</strong> costo <strong>de</strong> este caso es :<br />
C A 5 = AAi<br />
+ CS(<br />
A,<br />
r)<br />
o<br />
C A5<br />
= AAi<br />
+ 1 si <strong>el</strong> atributo es clave.<br />
A6. (Índice primario, <strong>de</strong>sigualdad): Si lo que se <strong>de</strong>sea es una s<strong>el</strong>ección <strong>de</strong>l tipo<br />
σ (r)<br />
con v disponible en <strong>el</strong> momento <strong>de</strong> la estimación <strong>de</strong>l costo y asumiendo<br />
A≤v<br />
que los datos <strong>de</strong>l atributo A se distribuyen uniformemente entonces, <strong>el</strong> número <strong>de</strong><br />
registros que cumplen con la <strong>de</strong>sigualdad es :<br />
n σ = 0 si v < min(A,r)<br />
n = n r si v > max(A,r)<br />
σ<br />
n σ =<br />
v − min( A,<br />
r)<br />
nr ⋅ en otro caso.<br />
max( A,<br />
r)<br />
− min( A,<br />
r)<br />
76
En cuanto al costo:<br />
Dado que <strong>el</strong> índice es primario se sabe que la tabla está or<strong>de</strong>nada por <strong>el</strong><br />
valor <strong>de</strong> la clave, por lo tanto, si <strong>el</strong> operador es > ó >= se realiza una búsqueda por<br />
<strong>el</strong> índice primario <strong>para</strong> encontrar a v en A y luego se realiza un recorrido lineal<br />
partiendo <strong>de</strong>s<strong>de</strong> esta tupla y hasta <strong>el</strong> fin <strong>de</strong> la tabla, lo que <strong>de</strong>volverá todas las<br />
tuplas que cumplen con la condición A >= v. Para una <strong>de</strong>sigualdad <strong>de</strong>l tipo < ó
No siempre es conveniente utilizar los índices <strong>para</strong> recuperar rangos <strong>de</strong><br />
valores, considérese <strong>el</strong> siguiente ejemplo:<br />
Supóngase que la la información estadística es la misma que se<br />
proporcionó anteriormente, que existe un índice B+ secundario <strong>para</strong> la columna<br />
TARIFA <strong>de</strong> la tabla viajes y que se <strong>de</strong>sea s<strong>el</strong>eccionar todas las tuplas <strong>de</strong> la tabla<br />
viajes que tengan una tarifa menor a 5000.<br />
Como <strong>el</strong> tamaño <strong>de</strong> la clave <strong>de</strong>l índice es <strong>de</strong> 4 bytes, es lógico pensar que<br />
en una página <strong>de</strong> índice caben 170 claves. Por lo tanto <strong>el</strong> índice necesita<br />
⎡log85 ( 36000)<br />
⎤<br />
= 3 accesos a bloques <strong>de</strong> disco <strong>para</strong> recuperar la primera hoja <strong>de</strong>l<br />
índice que se va a ocupar. Suponiendo que existen 600 valores distintos <strong>de</strong> tarifas,<br />
entonces existen entre 600/170 ≅ 4 a 8 nodos hojas en <strong>el</strong> árbol, por lo que, en <strong>el</strong><br />
peor <strong>de</strong> los casos se <strong>de</strong>ben leer 8/2 = 4 bloques <strong>de</strong> índices más 36000/2 = 18000<br />
accesos a bloques <strong>de</strong> datos. Por lo tanto, <strong>el</strong> costo <strong>de</strong> este camino <strong>de</strong> acceso es <strong>de</strong><br />
18000+4+3 = 18007.<br />
Por <strong>el</strong> contrario un full scan sobre la tabla empleará solamente b viaje = 2391<br />
bloques en vez <strong>de</strong> los 18007 calculados <strong>para</strong> <strong>el</strong> camino <strong>de</strong> acceso por índice<br />
secundario, por lo tanto, <strong>de</strong> presentarse este ejemplo, <strong>el</strong> optimizador <strong>de</strong> <strong>consultas</strong><br />
optará por un full scan.<br />
5.3.2. Conjunción, Disyunción y Negación.<br />
Conjunción.<br />
Una s<strong>el</strong>ección conjuntiva es expresión una <strong>de</strong> la forma<br />
σ θ 1∧<br />
θ 2...<br />
∧θm<br />
78<br />
( r)<br />
Suponiendo que cada una <strong>de</strong> las condiciones θi es in<strong>de</strong>pendiente <strong>de</strong> las otras se<br />
.
pue<strong>de</strong> estimar <strong>el</strong> tamaño <strong>de</strong> cada s<strong>el</strong>ección = σ (r ) . La probabilidad <strong>de</strong> que<br />
ti θi<br />
una tupla satisfaga la condición <strong>de</strong> s<strong>el</strong>ección es<br />
t<br />
n<br />
i<br />
r<br />
79<br />
(llamada s<strong>el</strong>ectividad <strong>de</strong> la<br />
s<strong>el</strong>ección) y la probabilidad <strong>de</strong> que una tupla satisfaga la conjunción <strong>de</strong><br />
s<strong>el</strong>ecciones es <strong>el</strong> producto <strong>de</strong> todas estas probabilida<strong>de</strong>s.<br />
Como<br />
Por lo tanto se estima <strong>el</strong> tamaño <strong>de</strong> la s<strong>el</strong>ección completa como:<br />
Disyunción.<br />
n<br />
r<br />
t<br />
⋅<br />
1<br />
⋅ t<br />
2<br />
⋅ t<br />
n<br />
3<br />
m<br />
r<br />
⋅ ... ⋅ t<br />
Una s<strong>el</strong>ección disyuntiva es una expresión <strong>de</strong> la forma<br />
ti <strong>de</strong>nota la probabilidad <strong>de</strong> que una tupla cumpla i<br />
n<br />
r<br />
m<br />
σ θ 1∨<br />
θ 2...<br />
∨θm<br />
( r)<br />
θ entonces, la<br />
probabilidad <strong>de</strong> que una tupla cumpla la disyunción es 1 menos la probabilidad <strong>de</strong><br />
que no cumpla ninguna <strong>de</strong> las condiciones.<br />
1 −<br />
( 1<br />
t1<br />
t 2 t m<br />
− ) ⋅ ( 1 − ) ⋅ ... ⋅ ( 1 − )<br />
n n n<br />
r<br />
por lo tanto, al multiplicar este valor por n r se obtiene <strong>el</strong> número <strong>de</strong> tuplas<br />
que satisfacen la r<strong>el</strong>ación.<br />
Negación.<br />
r<br />
r<br />
.
Como <strong>el</strong> resultado <strong>de</strong> una negación son simplemente las tuplas <strong>de</strong> r que no<br />
están en σ (r)<br />
, entonces <strong>el</strong> número <strong>de</strong> tuplas que cumplen con la condición <strong>de</strong><br />
θ<br />
negación es:<br />
tamaño θ<br />
( r)<br />
− tamaño(<br />
σ ( r))<br />
Algoritmos <strong>para</strong> la conjunción y disyunción.<br />
A8.(s<strong>el</strong>ección conjuntiva utilizando un índice simple): primero hay que<br />
<strong>de</strong>terminar si hay disponible un camino <strong>de</strong> acceso a una <strong>de</strong> las condiciones<br />
simples, <strong>de</strong> ser así, se pue<strong>de</strong> utilizar cualquier algoritmo <strong>de</strong>l A1 al A7. Luego, en<br />
memoria intermedia se verifica que los registros cumplan <strong>el</strong> resto <strong>de</strong> las<br />
condiciones. Se utiliza la s<strong>el</strong>ectividad <strong>de</strong> las condiciones <strong>para</strong> <strong>de</strong>terminar en que<br />
or<strong>de</strong>n efectuar las s<strong>el</strong>ecciones. La condición más s<strong>el</strong>ectiva (la que tiene la<br />
s<strong>el</strong>ectividad más pequeña) recupera un mayor número <strong>de</strong> registros, por lo tanto<br />
esta condición se <strong>de</strong>be comprobar en primer lugar.<br />
A9.(s<strong>el</strong>ección conjuntiva, índice compuesto): si la s<strong>el</strong>ección especifica una<br />
condición <strong>de</strong> igualdad en dos o más atributos y existe un índice compuesto en<br />
estos campos, se podría buscar en <strong>el</strong> índice directamente. El tipo <strong>de</strong> índice<br />
<strong>de</strong>termina cual <strong>de</strong> los algoritmos A3, A4 o A5 se utilizará.<br />
A10.(s<strong>el</strong>ección conjuntiva, intersección <strong>de</strong> i<strong>de</strong>ntificadores): este algoritmo<br />
utiliza índices con punteros a registros en los campos involucrados <strong>para</strong> cada<br />
condición individual. De este modo se examina cada índice en busca <strong>de</strong> punteros<br />
cuyas tuplas cumplan alguna condición individual. La intersección <strong>de</strong> todos los<br />
punteros recuperados forma <strong>el</strong> conjunto <strong>de</strong> punteros a tuplas que satisfacen la<br />
condición conjuntiva.<br />
80
A11. (s<strong>el</strong>ección disyuntiva mediante la unión <strong>de</strong> i<strong>de</strong>ntificadores): al igual que<br />
en <strong>el</strong> caso anterior se utilizan los caminos <strong>de</strong> acceso en cada una <strong>de</strong> las<br />
condiciones, la unión <strong>de</strong> los punteros forma <strong>el</strong> conjunto <strong>de</strong> punteros a tuplas que<br />
satisfacen la condición disyuntiva, sin embargo se <strong>de</strong>berá efectuar una búsqueda<br />
lineal si sólo una <strong>de</strong> las condiciones (o más) no tiene caminos <strong>de</strong> acceso.<br />
Ejemplo:<br />
Dada la consulta :<br />
SELECT * FROM VIAJES WHERE PATENTE = ‘HL-8483’ AND TARIFA = 2000<br />
Suponiendo que la información estadística es la misma <strong>de</strong> los ejemplos<br />
anteriores, si se utiliza <strong>el</strong> índice que contiene <strong>el</strong> atributo PATENTE se necesitan 83<br />
accesos a disco como se observo anteriormente.<br />
Si se utiliza <strong>el</strong> índice en TARIFA, como hay 600 valores diferentes en <strong>el</strong><br />
atributo tarifa, significa que CS(TARIFA,VIAJES) = 36000/600 = 60; por lo que en <strong>el</strong><br />
peor <strong>de</strong> los casos hay que leer 60 bloques <strong>de</strong> disco <strong>para</strong> recuperar cada una <strong>de</strong><br />
las tuplas. Se sabe a<strong>de</strong>más que la altura <strong>de</strong>l índice en <strong>el</strong> atributo tarifa es <strong>de</strong> 3, por<br />
lo tanto se necesitan sólo 60+3=63 accesos a disco a diferencia <strong>de</strong> las 83 que se<br />
necesitan por medio <strong>de</strong>l uso <strong>de</strong>l índice primario.<br />
Otra técnica que se pue<strong>de</strong> utilizar es la <strong>de</strong> intersección <strong>de</strong> i<strong>de</strong>ntificadores.<br />
Para este efecto se sabe que ambos índices tienen altura = 3. <strong>para</strong> <strong>el</strong> índice<br />
primario, <strong>el</strong> número <strong>de</strong> punteros a recuperar es 1200 los cuales caben en<br />
1200/100 = 12 bloques <strong>de</strong> índice, <strong>para</strong> <strong>el</strong> índice secundario <strong>el</strong> número <strong>de</strong> punteros<br />
a rescatar es <strong>de</strong> 60 los cuales caben en una sola página. Por lo que hasta <strong>el</strong><br />
momento se necesitan 6 + 12 + 1 = 19 bloques. Para los bloques <strong>de</strong> datos se<br />
81
necesita estimar la cantidad <strong>de</strong> tuplas que cumplen con la conjunción, como<br />
CS(PATENTE,VIAJES)=1200 y CS(TARIFA,VIAJES)=60 entonces se sabe que<br />
(1200*60)/36000 = 2 registros cumplen con la condición conjuntiva, los que en <strong>el</strong><br />
peor <strong>de</strong> los casos se rescatan con 2 accesos a bloques <strong>de</strong> disco, por lo tanto este<br />
algoritmo ocupa un total <strong>de</strong> 21 accesos a disco a diferencia <strong>de</strong> los 63 que ocupa <strong>el</strong><br />
camino <strong>de</strong> acceso <strong>de</strong>l índice secundario. Esta estimación se fundamenta en la<br />
suposición <strong>de</strong> que la distribución <strong>de</strong> los datos en PATENTES y en TARIFAS es<br />
in<strong>de</strong>pendiente y <strong>de</strong> que ambos atributos están distribuidos uniformemente en la<br />
r<strong>el</strong>ación.<br />
5.3.3. JOIN.<br />
Estimación <strong>de</strong>l tamaño.<br />
Sean r(R) y s(S) dos r<strong>el</strong>aciones:<br />
Si R I S=∅ entonces r s es lo mismo que r x s, y por lo tanto se pue<strong>de</strong><br />
utilizar la estimación <strong>de</strong>l producto cartesiano.<br />
Si R I S es una clave <strong>de</strong> R entonces <strong>el</strong> número <strong>de</strong> tuplas en r s no es<br />
mayor que <strong>el</strong> número <strong>de</strong> tuplas en S. Si R I S es una clave externa <strong>de</strong> R entonces <strong>el</strong><br />
número <strong>de</strong> tuplas <strong>de</strong> r s es exactamente <strong>el</strong> número <strong>de</strong> tuplas <strong>de</strong> S.<br />
Si R I S no es clave <strong>de</strong> R ni <strong>de</strong> S entonces se supone que cada valor<br />
aparece con la misma probabilidad , por lo tanto, sea t una tupla <strong>de</strong> r y sea<br />
R I S={A}, entonces se estima que la tupla t produce :<br />
ns<br />
CS(<br />
A,<br />
s)<br />
=<br />
V ( A,<br />
s)<br />
82
tuplas en s, por lo tanto se estima <strong>el</strong> tamaño <strong>de</strong> r s =<br />
al cambiar los pap<strong>el</strong>es <strong>de</strong> r y s se tiene<br />
nr ⋅ ns<br />
V ( A,<br />
r)<br />
nr ⋅ ns<br />
V ( A,<br />
s)<br />
Estos valores serán distintos si y sólo si V(A,r) ≠ V(A,s), si este es <strong>el</strong> caso, la<br />
más baja estimación <strong>de</strong> ambas será la más conveniente.<br />
Algoritmos.<br />
5.3.3.1. Join en bucles anidados.<br />
Si z = r s, r recibirá <strong>el</strong> nombre <strong>de</strong> r<strong>el</strong>ación externa y s se llamará r<strong>el</strong>ación<br />
interna, <strong>el</strong> algoritmo <strong>de</strong> bucles anidados se pue<strong>de</strong> presentar como sigue.<br />
resultado<br />
<strong>para</strong> cada tupla tr en r<br />
<strong>para</strong> cada tupla ts en s<br />
si (tr,ts) satisface la condición θ entonces añadir tr • ts al<br />
Algoritmo 5-1 - Join en bucles anidados.<br />
Don<strong>de</strong> tr • ts será la concatenación <strong>de</strong> las tuplas tr y ts .<br />
Como <strong>para</strong> cada registro <strong>de</strong> r se tiene que realizar una exploración<br />
completa <strong>de</strong> s, y suponiendo <strong>el</strong> peor caso, en <strong>el</strong> cual la memoria intermedia sólo<br />
pue<strong>de</strong> concatenar un bloque <strong>de</strong> cada r<strong>el</strong>ación, entonces <strong>el</strong> número <strong>de</strong> bloques a<br />
acce<strong>de</strong>r es <strong>de</strong> br + nr<br />
⋅ bs<br />
. Por otro lado, en <strong>el</strong> mejor <strong>de</strong> los casos si se pue<strong>de</strong>n<br />
(a)<br />
(b)<br />
83
contener ambas r<strong>el</strong>aciones en la memoria intermedia entonces sólo se<br />
necesitarían b r + bs<br />
accesos a bloques.<br />
Ahora bien, si la más pequeña <strong>de</strong> ambas r<strong>el</strong>aciones cabe completamente<br />
en la memoria, es conveniente utilizar esta r<strong>el</strong>ación como la r<strong>el</strong>ación interna,<br />
utilizando así sólo b r + bs<br />
accesos a bloques.<br />
5.3.3.2. Join en bucles anidados por bloques.<br />
Una variante <strong>de</strong>l algoritmo anterior pue<strong>de</strong> lograr un ahorro en <strong>el</strong> acceso a<br />
bloques si se procesan las r<strong>el</strong>aciones por bloques en vez <strong>de</strong> por tuplas.<br />
<strong>para</strong> cada bloque Br <strong>de</strong> r<br />
<strong>para</strong> cada bloque Bs <strong>de</strong> s<br />
<strong>para</strong> cada tupla tr en Br<br />
<strong>para</strong> cada tupla ts en Bs<br />
si (tr,ts) satisface la condición θ entonces añadir tr • ts<br />
al resultado<br />
Algoritmo 5-2 - Join en bucles anidados por bloques.<br />
La diferencia principal en costos <strong>de</strong> este algoritmo con <strong>el</strong> anterior es que en<br />
<strong>el</strong> peor <strong>de</strong> los casos cada bloque <strong>de</strong> la r<strong>el</strong>ación interna s se lee una vez por cada<br />
bloque <strong>de</strong> r y no por cada tupla <strong>de</strong> la r<strong>el</strong>ación externa, <strong>de</strong> este modo <strong>el</strong> número <strong>de</strong><br />
bloques a acce<strong>de</strong>r es <strong>de</strong> br + br<br />
⋅ bs<br />
don<strong>de</strong> a<strong>de</strong>más resulta más conveniente utilizar<br />
la r<strong>el</strong>ación más pequeña como la r<strong>el</strong>ación externa.<br />
84
5.3.3.3. Join en bucles anidados por índices.<br />
Este algoritmo simplemente sustituye las búsquedas en tablas por<br />
búsquedas en índices, esto pue<strong>de</strong> ocurrir siempre y cuando exista un índice en <strong>el</strong><br />
atributo <strong>de</strong> join <strong>de</strong> la r<strong>el</strong>ación interna. Este método se utiliza cuando existen<br />
índices así como cuando se crean índices temporales con <strong>el</strong> único propósito <strong>de</strong><br />
evaluar la reunión.<br />
El costo <strong>de</strong> este algoritmo se pue<strong>de</strong> calcular como sigue: <strong>para</strong> cada tupla <strong>de</strong><br />
la r<strong>el</strong>ación externa r se realiza una búsqueda en <strong>el</strong> índice <strong>de</strong> s <strong>para</strong> recuperar las<br />
tuplas apropiadas, sea c = costo <strong>de</strong> la búsqueda en <strong>el</strong> índice, <strong>el</strong> cual se pue<strong>de</strong><br />
calcular con cualquiera <strong>de</strong> los algoritmos A3, A4 o A5. Entonces <strong>el</strong> costo <strong>de</strong>l join<br />
es + n ⋅ c ; si hay índices disponibles <strong>para</strong> <strong>el</strong> atributo <strong>de</strong> join en ambas<br />
br r<br />
r<strong>el</strong>aciones, es conveniente utilizar la r<strong>el</strong>ación con menos tuplas.<br />
5.3.3.4. Join por mezcla.<br />
El algoritmo <strong>de</strong> Join por mezcla se pu<strong>de</strong> utilizar <strong>para</strong> calcular un Join natural<br />
o un equi-join. Para tales efectos ambas r<strong>el</strong>aciones <strong>de</strong>ben estar or<strong>de</strong>nadas por los<br />
atributos en común.<br />
Este algoritmo asocia un puntero a cada r<strong>el</strong>ación, al principio estos punteros<br />
apuntan al inicio <strong>de</strong> cada una <strong>de</strong> la r<strong>el</strong>aciones. Según avanza <strong>el</strong> algoritmo, <strong>el</strong><br />
puntero se mueve a través <strong>de</strong> la r<strong>el</strong>ación. De este modo se leen en memoria un<br />
grupo <strong>de</strong> tuplas <strong>de</strong> una r<strong>el</strong>ación con <strong>el</strong> mismo valor en los atributos <strong>de</strong> la reunión.<br />
85
Pr = dirección <strong>de</strong> la primera tupla <strong>de</strong> r;<br />
ps = dirección <strong>de</strong> la primera tupla <strong>de</strong> s;<br />
mientras (ps nulo y pr nulo)<br />
inicio<br />
ts = tupla a la que apunta ps;<br />
S = {ts};<br />
ps = puntero a la siguiente tupla <strong>de</strong> s;<br />
hecho = falso;<br />
mientras (not hecho y ps nulo)<br />
inicio<br />
ts' = tupla a la que apunta ps;<br />
si (ts'[AtribsReunión] = ts[AtribsReunión])<br />
S = S union {ts'};<br />
ps = puntero a la siguiente tupla <strong>de</strong> s;<br />
sino<br />
hecho = verda<strong>de</strong>ro;<br />
fin mientras;<br />
tr = tupla a la que apunta pr;<br />
mientras (pr nulo y tr[AtribsReunión] < ts[AtribsReunión])<br />
inicio<br />
pr = puntero a la siguiente tupla <strong>de</strong> r;<br />
tr = tupla a la que apunta pr;<br />
fin mientras;<br />
mientras (pr nulo y tr[AtribsReunión] = ts[AtribsReunión])<br />
inicio<br />
<strong>para</strong> cada ts en S<br />
añadir ts x tr al resultado<br />
pr = puntero a la siguiente tupla <strong>de</strong> r;<br />
tr = tupla a la que apunta pr;<br />
fin mientras<br />
fin mientras<br />
Algoritmo 5-3 - Join por mezcla.<br />
86
Dado que las r<strong>el</strong>aciones están or<strong>de</strong>nadas, las tuplas con <strong>el</strong> mismo valor en<br />
los atributos <strong>de</strong> la reunión aparecerán consecutivamente. De este modo solamente<br />
es necesario leer cada tupla en <strong>el</strong> or<strong>de</strong>n una sola vez. Puesto que sólo se hace un<br />
ciclo en ambas tablas, este método resulta eficiente; <strong>el</strong> número <strong>de</strong> accesos a<br />
bloques <strong>de</strong> disco es igual a la suma <strong>de</strong> los bloques <strong>de</strong> las dos tablas b r + bs<br />
. Si<br />
una <strong>de</strong> las r<strong>el</strong>aciones no está or<strong>de</strong>nada según los atributos comunes <strong>de</strong>l join, se<br />
pue<strong>de</strong> or<strong>de</strong>nar primero <strong>para</strong> luego utilizar <strong>el</strong> algoritmo <strong>de</strong> join por mezcla. En este<br />
caso hay que consi<strong>de</strong>rar también <strong>el</strong> costo <strong>de</strong> or<strong>de</strong>nar la o las r<strong>el</strong>aciones y sumarlo<br />
al costo <strong>de</strong> este algoritmo. Como se menciono anteriormente este algoritmo<br />
necesita que <strong>el</strong> conjunto S <strong>de</strong> tuplas quepa completamente en la memoria<br />
principal, este requisito se pue<strong>de</strong> alcanzar normalmente, incluso si la r<strong>el</strong>ación s es<br />
gran<strong>de</strong>. De no po<strong>de</strong>r cumplirse este requisito se <strong>de</strong>berá efectuar un join en bucle<br />
anidado por bloques entre {S} y r con los mismos valores en los atributos <strong>de</strong>l join,<br />
con lo que <strong>el</strong> costo <strong>de</strong>l join aumenta.<br />
Una variación <strong>de</strong> este algoritmo se pue<strong>de</strong> realizar aún en tuplas<br />
<strong>de</strong>sor<strong>de</strong>nadas si existen índices secundarios en los atributos <strong>de</strong> join <strong>de</strong> cada una<br />
<strong>de</strong> las r<strong>el</strong>aciones, sin embargo, dada la naturaleza <strong>de</strong> este tipo <strong>de</strong> caminos <strong>de</strong><br />
acceso existe una alta probabilidad <strong>de</strong> que se necesite un acceso a bloque <strong>de</strong><br />
disco por cada tupla, lo que lo hace sustancialmente más costoso. Para evitar este<br />
costo se pue<strong>de</strong> utilizar un algoritmo <strong>de</strong> join por mezcla híbrido, que combina<br />
índices con un join por mezcla. Si sólo una <strong>de</strong> las r<strong>el</strong>aciones está <strong>de</strong>sor<strong>de</strong>nada<br />
pero existe un índice secundario en <strong>el</strong> atributo <strong>de</strong> join, <strong>el</strong> algoritmo <strong>de</strong> join por<br />
mezcla híbrido combina la r<strong>el</strong>ación or<strong>de</strong>nada con las entradas hojas <strong>de</strong>l índice<br />
secundario. El resultado <strong>de</strong> esta operación se <strong>de</strong>be or<strong>de</strong>nar según las direcciones<br />
<strong>de</strong>l índice secundario permitiendo así una recuperación eficiente <strong>de</strong> las tuplas,<br />
según <strong>el</strong> or<strong>de</strong>n físico <strong>de</strong> almacenamiento.<br />
87
5.3.3.5. Join por asociación.<br />
Al igual que <strong>el</strong> algoritmo <strong>de</strong> join por mezcla, <strong>el</strong> algoritmo <strong>de</strong> join por<br />
asociación se pue<strong>de</strong> utilizar <strong>para</strong> un Join natural o un equi-join. Este algoritmo<br />
utiliza una función <strong>de</strong> asociación h <strong>para</strong> dividir las tuplas <strong>de</strong> ambas r<strong>el</strong>aciones. La<br />
i<strong>de</strong>a fundamental es dividir las tuplas <strong>de</strong> cada r<strong>el</strong>ación en conjuntos con <strong>el</strong> mismo<br />
valor <strong>de</strong> la función <strong>de</strong> asociación en los atributos <strong>de</strong> join.<br />
Se supone que:<br />
• h es una función <strong>de</strong> asociación que asigna a los atributos <strong>de</strong> join los valores<br />
•<br />
{0,1,...max}<br />
• r , H ,...<br />
0 r H 1 rmax<br />
H <strong>de</strong>notan las particiones <strong>de</strong> las tuplas <strong>de</strong> r, inicialmente todas<br />
vacías. Cada tupla r t se pone en la partición H r don<strong>de</strong><br />
i<br />
( t [ Atributos _ <strong>de</strong> Join]<br />
)<br />
i = h r _<br />
• H s , H s ,... H s <strong>de</strong>notan las particiones <strong>de</strong> las tuplas <strong>de</strong> s, inicialmente todas<br />
0 1<br />
max<br />
vacías. Cada tupla ts se pone en la partición H s don<strong>de</strong><br />
i<br />
( t [ Atributos _ <strong>de</strong> Join]<br />
)<br />
i = h s _<br />
La i<strong>de</strong>a <strong>de</strong>trás <strong>de</strong>l algoritmo es la siguiente, supóngase que una tupla <strong>de</strong> r y<br />
una tupla <strong>de</strong> s satisfacen la condición <strong>de</strong> join y por lo tanto tienen los mismos<br />
valores en los atributos <strong>de</strong> join. Si estos valores se asocian con algún valor i,<br />
entonces la tupla <strong>de</strong> r tiene que estar en H r y la tupla <strong>de</strong> s tiene que estar en H i<br />
s , i<br />
<strong>de</strong> este modo sólo será necesario com<strong>para</strong>r las tuplas <strong>de</strong> r en H r con las tuplas<br />
i<br />
<strong>de</strong> s en H s y no con las tuplas <strong>de</strong> s <strong>de</strong> otra partición.<br />
i<br />
88
tuplas<br />
t r<br />
El algoritmo es <strong>el</strong> siguiente.<br />
<strong>para</strong> cada tupla t s en s<br />
fin <strong>para</strong>;<br />
( t [ Atributos _ <strong>de</strong> Join]<br />
)<br />
i = h s _ ;<br />
= H s U{<br />
ts}<br />
;<br />
H si<br />
i<br />
<strong>para</strong> cada tupla tr en r<br />
( t [ Atributos _ <strong>de</strong> Join]<br />
)<br />
i = h r _ ;<br />
= H r U{<br />
tr}<br />
;<br />
H ri<br />
i<br />
fin <strong>para</strong>;<br />
<strong>para</strong> i = 1 hasta max<br />
[ Atributos <strong>de</strong> _ Join]<br />
leer H s y construir un índice asociativo en memoria sobre él;<br />
i<br />
<strong>para</strong> cada tupla tr en H ri<br />
_ ;<br />
fin <strong>para</strong>;<br />
fin <strong>para</strong>;<br />
fin <strong>para</strong>;<br />
explorar <strong>el</strong> índice asociativo en H s <strong>para</strong> localizar todas las<br />
i<br />
tales que [ Atributos <strong>de</strong> _ Join]<br />
<strong>para</strong> cada tupla ts que concuer<strong>de</strong> en H si<br />
añadir tr x ts al resultado;<br />
t s<br />
Algoritmo 5-4 - Join por asociación.<br />
_ =<br />
89
El índice asociativo (ver Apéndice B) en H s se construye en memoria por lo<br />
i<br />
que no se hace necesario acce<strong>de</strong>r al disco <strong>para</strong> recuperar las tuplas, la función <strong>de</strong><br />
asociación utilizada <strong>para</strong> construir este índice es distinta a la función h utilizada<br />
<strong>para</strong> construir las particiones. Después <strong>de</strong> la división <strong>de</strong> las r<strong>el</strong>aciones <strong>el</strong> resto <strong>de</strong>l<br />
código realiza un join en bucle anidado por índices en cada una <strong>de</strong> las particiones.<br />
Para lograr esto primero se construye un índice asociativo en cada H s y luego se<br />
i<br />
prueba (se busca en H s ) con las tuplas <strong>de</strong> H i<br />
r . i<br />
Se tiene que <strong>el</strong>egir <strong>el</strong> valor <strong>de</strong> max lo suficientemente gran<strong>de</strong> como <strong>para</strong><br />
que, <strong>para</strong> cada i, las tuplas <strong>de</strong> la partición H s junto con <strong>el</strong> índice asociativo <strong>de</strong> la<br />
i<br />
r<strong>el</strong>ación quepan completamente en la memoria. Claramente será más conveniente<br />
utilizar la r<strong>el</strong>ación más pequeña como la r<strong>el</strong>ación s. Si <strong>el</strong> tamaño <strong>de</strong> la r<strong>el</strong>ación s es<br />
bs bloques, entonces <strong>para</strong> que cada una <strong>de</strong> las max particiones tengan un tamaño<br />
menor o igual a M, max <strong>de</strong>be ser al menos ⎡bs / M ⎤ más <strong>el</strong> espacio adicional<br />
ocupado por <strong>el</strong> índice asociativo. Una consi<strong>de</strong>ración a seguir <strong>para</strong> que las<br />
divisiones <strong>de</strong> las r<strong>el</strong>aciones se efectúe en un solo paso es que M>max+1 o<br />
equivalentemente si M>( b/M)+1 s que <strong>de</strong> manera aproximada se simplifica a<br />
M > bs<br />
. Por ejemplo, si una r<strong>el</strong>ación contiene 440 bloques <strong>de</strong> 2KB cada uno,<br />
entonces M > 440 , osea M > 20. De tal manera sólo se necesitarán 40 Kb. <strong>de</strong><br />
espacio <strong>de</strong> memoria (más <strong>el</strong> espacio requerido por <strong>el</strong> índice asociativo) <strong>para</strong> <strong>el</strong><br />
particionamiento <strong>de</strong> la r<strong>el</strong>ación.<br />
El cálculo <strong>de</strong>l costo <strong>de</strong> un join por asociación tiene la siguiente lógica: <strong>el</strong><br />
particionamiento <strong>de</strong> ambas r<strong>el</strong>aciones reclama una lectura completa <strong>de</strong> cada<br />
r<strong>el</strong>ación, como también su posterior escritura, esta operación necesita 2( b r + bs<br />
)<br />
accesos a bloques. Las fases <strong>de</strong> construcción y prueba (como se le <strong>de</strong>nomina al<br />
join en bucle anidado por índices) lee cada una <strong>de</strong> las particiones una vez<br />
90
empleando b r + bs<br />
accesos adicionales. El número <strong>de</strong> bloques ocupados por las<br />
particiones podría ser ligeramente mayor que b r + bs<br />
. Debido a que los bloques no<br />
están completamente llenos,. El acceso a estos bloques pue<strong>de</strong> añadir un gasto<br />
adicional <strong>de</strong> 2·max a lo sumo, ya que cada una <strong>de</strong> las particiones podría tener un<br />
bloque parcialmente ocupado que se tiene que leer y escribir <strong>de</strong> nuevo. Así <strong>el</strong><br />
costo estimado <strong>para</strong> un join por asociación es :<br />
3( b r + bs<br />
) + 2 ⋅ max<br />
5.3.3.6. Join por asociación híbrida.<br />
El algoritmo <strong>de</strong> join por asociación híbrida realiza otra optimización; es útil<br />
cuando <strong>el</strong> tamaño <strong>de</strong> la memoria es r<strong>el</strong>ativamente gran<strong>de</strong> paro aún así, no cabe<br />
toda la r<strong>el</strong>ación s en memoria. Dado que <strong>el</strong> algoritmo <strong>de</strong> join por asociación<br />
necesita max +1 bloques <strong>de</strong> memoria <strong>para</strong> dividir ambas r<strong>el</strong>aciones se pue<strong>de</strong><br />
utilizar <strong>el</strong> resto <strong>de</strong> la memoria (M – max – 1 bloques) <strong>para</strong> guardar en la memoria<br />
intermedia la primera partición <strong>de</strong> la r<strong>el</strong>ación s, esto es H s , así no es necesaria<br />
0<br />
leerla ni escribirla nuevamente y se pue<strong>de</strong> construir un índice asociativo en H s . 0<br />
Cuando r se divi<strong>de</strong>, las tuplas <strong>de</strong> H r tampoco se escriben en disco; en su<br />
0<br />
lugar, según se van generando, <strong>el</strong> sistema las utiliza <strong>para</strong> examinar <strong>el</strong> índice<br />
asociativo en H s y así generar las tuplas <strong>de</strong> salida <strong>de</strong>l join. Después <strong>de</strong> utilizarlas,<br />
0<br />
estas tuplas se <strong>de</strong>scartan, así que la partición H r no ocupa espacio en memoria.<br />
0<br />
De este modo se ahorra un acceso <strong>de</strong> lectura y uno <strong>de</strong> escritura <strong>para</strong> cada bloque<br />
<strong>de</strong> H r y H 0 s . Las tuplas <strong>de</strong> otras particiones se escriben <strong>de</strong> la manera usual <strong>para</strong><br />
0<br />
reunirlas más tar<strong>de</strong>.<br />
91
5.3.3.7. Join Complejos.<br />
Los join en bucle anidado y en bucle anidado por bloques son útiles<br />
siempre, sin embargo, las otras técnicas <strong>de</strong> join son más eficientes que estas,<br />
pero sólo se pue<strong>de</strong>n utilizar en condiciones particulares tales como join natural o<br />
equi-join. Se pue<strong>de</strong>n implementar join con condiciones más complejas tales como<br />
conjunción o disyunción, aplicando las técnicas <strong>de</strong>sarrolladas en la sección 5.3.2<br />
<strong>para</strong> <strong>el</strong> manejo <strong>de</strong> s<strong>el</strong>ecciones complejas.<br />
Dado un join <strong>de</strong> las forma r θ ∧ θ ∧...<br />
∧θ<br />
s se pue<strong>de</strong>n aplicar una o más <strong>de</strong> las<br />
1 2 n<br />
técnicas <strong>de</strong> join <strong>de</strong>scritas anteriormente en cada condición individual r θ s , <strong>el</strong><br />
i<br />
resultado total consiste en las tuplas <strong>de</strong>l resultado intermedio que satisfacen <strong>el</strong><br />
resto <strong>de</strong> las condiciones. Estas condiciones se pue<strong>de</strong>n ir comprobado según se<br />
generen las tuplas <strong>de</strong> r θ s . La implementación <strong>de</strong> la disyunción es homóloga a<br />
i<br />
la conjunción.<br />
Outer Join (Join externos)<br />
Un outer join es una extensión <strong>de</strong>l operador join que se utiliza a menudo<br />
<strong>para</strong> trabajar con la información que falta. Por ejemplo, suponiendo que se <strong>de</strong>sea<br />
generar una lista con todos los choferes y los autos que manejan (si manejan<br />
alguno) entonces se <strong>de</strong>be cruzar la r<strong>el</strong>ación Chofer con la r<strong>el</strong>ación Movil. Si se<br />
efectúa un join corriente se per<strong>de</strong>rán todas aqu<strong>el</strong>las tuplas que pertenecen a los<br />
choferes, en cambio con un outer join se pue<strong>de</strong>n <strong>de</strong>splegar las tuplas resultado<br />
incluyendo a aqu<strong>el</strong>los choferes que no tengan a cargo un auto. El outer join tiene<br />
tres formas distintas: por la izquierda, por la <strong>de</strong>recha y completo. El join por la<br />
izquierda ( ]x )toma todas las tuplas <strong>de</strong> la r<strong>el</strong>ación <strong>de</strong> la izquierda que no<br />
92
coincidan con ninguna tupla <strong>de</strong> la r<strong>el</strong>ación <strong>de</strong> la <strong>de</strong>recha , las r<strong>el</strong>lena con valores<br />
nulos en los <strong>de</strong>más atributos <strong>de</strong> la r<strong>el</strong>ación <strong>de</strong> la <strong>de</strong>recha y las aña<strong>de</strong> al resultado<br />
<strong>de</strong>l join natural. Un outer join por la <strong>de</strong>recha ( x [ ) ) es análogo al procedimiento<br />
anterior y <strong>el</strong> outer join completo es aqu<strong>el</strong> que efectúa ambas operaciones.<br />
Se pue<strong>de</strong> implementar un outer join empleando una <strong>de</strong> las dos estrategias<br />
siguientes. La primera efectúa un join natural y luego aña<strong>de</strong> más tuplas al<br />
resultado hasta obtener <strong>el</strong> join externo. Sea r(R) y s(S) , <strong>para</strong> evaluar r ] x s se<br />
calcula primero r s y se guarda este resultado en la r<strong>el</strong>ación temporal q1, a<br />
continuación se calcula (q1)<br />
∏ − que produce las tuplas <strong>de</strong> r que no participan<br />
r R<br />
<strong>de</strong>l join, estas tuplas se r<strong>el</strong>lenan con valores nulos en los atributos <strong>de</strong> s y se<br />
aña<strong>de</strong>n a q1 <strong>para</strong> obtener <strong>el</strong> resultado <strong>de</strong>seado. El procedimiento es homólogo<br />
<strong>para</strong> los outer join por la <strong>de</strong>recha o completo.<br />
La segunda estrategia significa modificar <strong>el</strong> algoritmo <strong>de</strong> join. Se pu<strong>de</strong><br />
exten<strong>de</strong>r <strong>el</strong> algoritmo <strong>de</strong> join en bucles anidados <strong>para</strong> calcular <strong>el</strong> outer join por la<br />
izquierda. Las tuplas <strong>de</strong> la r<strong>el</strong>ación externa que no concuer<strong>de</strong>n con ninguna tupla<br />
<strong>de</strong> la r<strong>el</strong>ación interna se completan con valores nulos y se escriben en la salida.<br />
Para <strong>el</strong> caso <strong>de</strong> un outer join completo se pue<strong>de</strong> calcular mediante<br />
extensiones <strong>de</strong> los algoritmos <strong>de</strong> join por mezcla y join por asociación. En <strong>el</strong> caso<br />
<strong>de</strong>l algoritmo <strong>de</strong> join por mezcla, cuando se está produciendo la mezcla <strong>de</strong> ambas<br />
r<strong>el</strong>aciones, las tuplas <strong>de</strong> la r<strong>el</strong>ación que no encajan con ninguna tupla <strong>de</strong> la otra<br />
r<strong>el</strong>ación se r<strong>el</strong>lenan con valores nulos y se escriben en la salida. Puesto que las<br />
r<strong>el</strong>aciones están or<strong>de</strong>nadas, es fácil <strong>de</strong>tectar si una tupla coinci<strong>de</strong> o no con alguna<br />
tupla <strong>de</strong> la otra r<strong>el</strong>ación. El costo estimado <strong>para</strong> realizar un outer join utilizando <strong>el</strong><br />
algoritmo <strong>de</strong> join por mezcla es <strong>el</strong> mismo que si fuera un join normal, la única<br />
diferencia es <strong>el</strong> tamaño <strong>de</strong>l resultado, por lo tanto <strong>el</strong> número <strong>de</strong> bloques a escribir<br />
en <strong>el</strong> resultado pue<strong>de</strong> aumentar.<br />
93
5.3.3.8. Agregación.<br />
La agregación es otra <strong>de</strong> las características <strong>de</strong>l álgebra <strong>de</strong> r<strong>el</strong>aciones<br />
extendida. La i<strong>de</strong>a <strong>de</strong> este tipo <strong>de</strong> funciones es que tomen un conjunto <strong>de</strong> valores<br />
y que retornen un solo valor. se utilizan comúnmente <strong>para</strong> información agregada<br />
(<strong>de</strong> ahí su nombre), analizan una agrupación <strong>de</strong> registros y rescatan <strong>el</strong> valor<br />
solicitado, se aplican sobre un atributo o sobre una composición <strong>de</strong> atributos, <strong>el</strong><br />
valor retornado pue<strong>de</strong> ser min, max, count, sum, avg, que correspon<strong>de</strong>n<br />
respectivamente a <strong>el</strong> mínimo valor <strong>de</strong>l subconjunto; <strong>el</strong> máximo valor; una cuenta<br />
<strong>de</strong> valores; la suma sobre algún atributo o composición <strong>de</strong> atributos y <strong>el</strong> promedio.<br />
Para la implementación <strong>de</strong> la operación <strong>de</strong> agregación se pue<strong>de</strong> utilizar un<br />
algoritmo <strong>de</strong> or<strong>de</strong>nación o uno <strong>de</strong> asociación, <strong>para</strong> <strong>el</strong> caso <strong>de</strong> la asociación, lo que<br />
se hace es agrupar las tuplas que tengan <strong>el</strong> mismo valor en los atributos <strong>de</strong> la<br />
agregación y luego se aplica la función <strong>de</strong> agregación en cada uno <strong>de</strong> los grupos<br />
<strong>para</strong> obtener <strong>el</strong> resultado.<br />
El tamaño <strong>de</strong> la agregación sobre A es simplemente V(A,r). El costo<br />
estimado <strong>de</strong> la implementación <strong>de</strong> la agregación es <strong>el</strong> mismo <strong>de</strong> una or<strong>de</strong>nación<br />
(cualquiera sea <strong>el</strong> algoritmo).<br />
En lugar <strong>de</strong> reunir todas las tuplas en grupos y aplicar entonces las<br />
funciones <strong>de</strong> agregación, se pue<strong>de</strong>n implementar sobre la marcha según se<br />
construyen los grupos. Si las V(A,r) tuplas <strong>de</strong>l resultado caben en memoria, las<br />
implementaciones basadas en or<strong>de</strong>nación y las basadas en asociación no<br />
requieren escribir bloques adicionales a disco, según se leen las tuplas se pue<strong>de</strong>n<br />
ir insertando en una estructura or<strong>de</strong>nada <strong>de</strong> árbol o en un índice asociativo, <strong>de</strong><br />
esta manera sólo se necesitan b r transferencias <strong>de</strong> bloques.<br />
94
5.4. Evaluación <strong>de</strong> expresiones.<br />
En este apartado se consi<strong>de</strong>rará como evaluar una expresión que contiene<br />
varias operaciones, la forma intuitiva <strong>de</strong> evaluar una expresión es evaluar una<br />
operación a la vez en un or<strong>de</strong>n apropiado, <strong>el</strong> resultado <strong>de</strong> cada operación se<br />
materializa en una r<strong>el</strong>ación temporal <strong>para</strong> su inmediata utilización. El<br />
inconveniente <strong>de</strong> esta aproximación es la creación <strong>de</strong> r<strong>el</strong>aciones temporales que<br />
implican la escritura y lectura <strong>de</strong> disco. Una aproximación alternativa es evaluar<br />
operaciones <strong>de</strong> manera simultanea en un cauce, con los resultados <strong>de</strong> una<br />
operación pasados a la siguiente sin la necesidad <strong>de</strong> almacenarlos en r<strong>el</strong>aciones<br />
temporales.<br />
5.4.1. Materialización.<br />
Este enfoque <strong>de</strong> implementación toma la expresión y la representa en una<br />
estructura anexa (comúnmente un árbol <strong>de</strong> operadores). Luego se comienza por<br />
las operaciones <strong>de</strong> más bajo niv<strong>el</strong>, las entradas a estas operaciones son las<br />
r<strong>el</strong>aciones <strong>de</strong> la base <strong>de</strong> datos, estas operaciones se ejecutan utilizando los<br />
algoritmos ya estudiados y almacenando sus resultados en r<strong>el</strong>aciones temporales.<br />
Luego se utilizan estas r<strong>el</strong>aciones temporales <strong>para</strong> ejecutar las operaciones <strong>de</strong>l<br />
siguiente niv<strong>el</strong> en <strong>el</strong> árbol.<br />
Una evaluación como la <strong>de</strong>scrita se llama evaluación materializada, puesto<br />
que los resultados <strong>de</strong> cada operación intermedia se crean (materializan) con <strong>el</strong> fin<br />
<strong>de</strong> ser utilizados en la evaluación <strong>de</strong> las operaciones <strong>de</strong>l siguiente niv<strong>el</strong>.<br />
95
El costo <strong>de</strong> una evaluación materializada no es simplemente la suma <strong>de</strong> los<br />
costos <strong>de</strong> las operaciones involucradas. Dado que los costos estimados <strong>de</strong> los<br />
algoritmos presentados anteriormente no consi<strong>de</strong>ran <strong>el</strong> resultado <strong>de</strong> la operación<br />
en disco, por lo tanto, al costo <strong>de</strong> las operaciones involucradas hay que añadir <strong>el</strong><br />
costo <strong>de</strong> escribir los resultados intermedios en disco. Suponiendo que los registros<br />
<strong>de</strong>l resultado se almacenan en una memoria intermedia y que cuando esta se<br />
llena, los registros se escriben en <strong>el</strong> disco. El costo <strong>de</strong> copiar los resultados se<br />
pue<strong>de</strong> estimar en r r b n don<strong>de</strong> nr es <strong>el</strong> número aproximado <strong>de</strong> tuplas <strong>de</strong> la r<strong>el</strong>ación<br />
resultado y fr es <strong>el</strong> factor <strong>de</strong> bloqueo <strong>de</strong> la r<strong>el</strong>ación resultado.<br />
5.4.2. Encauzamiento.<br />
Se pue<strong>de</strong> mejorar la evaluación <strong>de</strong> una consulta mediante la reducción <strong>de</strong>l<br />
número <strong>de</strong> archivos temporales que se producen. Por ejemplo, considérese <strong>el</strong> join<br />
<strong>de</strong> dos r<strong>el</strong>aciones seguida <strong>de</strong> una proyección. Si se aplicara materialización en la<br />
evaluación <strong>de</strong> esta expresión implicaría la creación <strong>de</strong> una r<strong>el</strong>ación temporal <strong>para</strong><br />
guardar <strong>el</strong> resultado <strong>de</strong>l join y la posterior lectura <strong>de</strong> esta <strong>para</strong> realizar la<br />
proyección. Estas operaciones se pue<strong>de</strong>n combinar como sigue. Cuando la<br />
operación <strong>de</strong> join genera una tupla <strong>de</strong>l resultado, esta se pasa inmediatamente al<br />
operador <strong>de</strong> proyección <strong>para</strong> su procesamiento. Mediante la combinación <strong>de</strong>l join y<br />
<strong>de</strong> la proyección, se evita la creación <strong>de</strong> resultados intermedios, creando en su<br />
lugar <strong>el</strong> resultado final directamente.<br />
La implementación <strong>de</strong>l encauzamiento se pue<strong>de</strong> realizar <strong>de</strong> dos formas:<br />
1. Bajo <strong>de</strong>manda (enfoque top-down)<br />
2. Des<strong>de</strong> los procedimientos (enfoque bottom-up)<br />
96
En un encauzamiento bajo <strong>de</strong>manda <strong>el</strong> sistema reitera peticiones <strong>de</strong> tuplas<br />
<strong>de</strong>s<strong>de</strong> la operación <strong>de</strong> la cima <strong>de</strong>l encauzamiento. Cada vez que un operador<br />
recibe una petición <strong>de</strong> tuplas calcula la siguiente tupla a <strong>de</strong>volver y la envía al<br />
procesador <strong>de</strong> <strong>consultas</strong>. En un encauzamiento <strong>de</strong>s<strong>de</strong> los procedimientos, los<br />
operadores no esperan a que se produzcan peticiones <strong>para</strong> producir las tuplas, en<br />
su lugar generan las tuplas impacientemente. Cada operación <strong>de</strong>l fondo <strong>de</strong>l<br />
encauzamiento genera continuamente tuplas <strong>de</strong> salida y las coloca en las<br />
memorias intermedias <strong>de</strong> salida hasta que se llenan. Asi, cuando un operador en<br />
cualquier niv<strong>el</strong> <strong>de</strong>l encauzamiento obtiene sus tuplas <strong>de</strong> entrada <strong>de</strong> un niv<strong>el</strong><br />
inferior <strong>de</strong>l encauzamiento, produce las tuplas <strong>de</strong> salida hasta llenar su memoria<br />
intermedia <strong>de</strong> salida.<br />
El sistema necesita cambiar <strong>de</strong> una operación a otra solamente cuando se<br />
llena una memoria intermedia <strong>de</strong> salida o cuando una memoria intermedia <strong>de</strong><br />
entrada está vacía y se necesitan más tuplas <strong>de</strong> entrada <strong>para</strong> generar las tuplas<br />
<strong>de</strong> salida. Las operaciones <strong>de</strong> encauzamiento se pue<strong>de</strong>n ejecutar<br />
concurrentemente en distintos procesadores.<br />
El encauzamiento bajo <strong>de</strong>manda se utiliza comúnmente más que <strong>el</strong><br />
encauzamiento <strong>de</strong>s<strong>de</strong> los procedimientos dada su facilidad <strong>de</strong> implementación.<br />
5.4.3. Algoritmos <strong>de</strong> encauzamiento.<br />
Supóngase un join cuya entrada <strong>de</strong>l lado izquierdo esta encauzada, dado<br />
que esta entrada no está completamente disponible, implica la imposibilidad e<br />
utilizar un join por mezcla (dado que no se sabe si la esta entrada viene o no<br />
or<strong>de</strong>nada). El or<strong>de</strong>nar la r<strong>el</strong>ación significa transformar <strong>el</strong> procedimiento en<br />
materialización. Este ejemplo ilustra que la <strong>el</strong>ección respecto al algoritmo a utilizar<br />
97
<strong>para</strong> una operación y las <strong>el</strong>ecciones respecto <strong>de</strong>l encauzamiento son<br />
<strong>de</strong>pendientes una <strong>de</strong> la otra.<br />
El uso eficiente <strong>de</strong>l encauzamiento necesita la utilización <strong>de</strong> algoritmos <strong>de</strong><br />
evaluación que puedan generar tuplas <strong>de</strong> salida según se están recibiendo tuplas<br />
por la entrada <strong>de</strong> la operación. Se pue<strong>de</strong>n distinguir dos casos:<br />
1. Solamente una <strong>de</strong> las entradas está encauzada.<br />
2. Las dos entradas <strong>de</strong> un join están encauzadas.<br />
Si únicamente una <strong>de</strong> las entradas está encauzada, un join en bucle<br />
anidado in<strong>de</strong>xado es la <strong>el</strong>ección más natural, ahora bien, si se sabe <strong>de</strong> antemano<br />
que las tuplas <strong>de</strong> la entrada encauzada están or<strong>de</strong>nadas por los atributos <strong>de</strong> join y<br />
la condición <strong>de</strong> join es un equi-join también se pue<strong>de</strong> usar un join por mezcla. Se<br />
pue<strong>de</strong> utilizar un join por asociación híbrida con la entrada encauzada como la<br />
r<strong>el</strong>ación <strong>para</strong> probar (r<strong>el</strong>ación r). Sin embargo, las tuplas que no están en la<br />
primera partición se enviarán a la salida solamente <strong>de</strong>spués <strong>de</strong> que la r<strong>el</strong>ación <strong>de</strong><br />
entrada encauzada se reciba por completo. Un join por asociación híbrida es útil si<br />
la entrada no encauzada cabe completamente en memoria, o si al menos la<br />
mayoría <strong>de</strong> las entradas caben en memoria.<br />
Si ambas entradas están encauzadas, la <strong>el</strong>ección <strong>de</strong> los algoritmos <strong>de</strong> join<br />
se limita. Si ambas entradas están or<strong>de</strong>nadas por <strong>el</strong> atributo <strong>de</strong> join y la condición<br />
<strong>de</strong> join es un equi-join entonces se pue<strong>de</strong> utilizar <strong>el</strong> método <strong>de</strong> join por mezcla.<br />
Otra técnica alternativa es <strong>el</strong> join por encauzamiento que se presenta a<br />
continuación. El algoritmo supone que las tuplas <strong>de</strong> entrada <strong>de</strong> ambas r<strong>el</strong>aciones r<br />
y s están encauzadas. Las tuplas disponibles <strong>de</strong> ambas r<strong>el</strong>aciones se <strong>de</strong>jan listas<br />
<strong>para</strong> su procesamiento en una estructura <strong>de</strong> cola simple. Asimismo se generan<br />
marcas especiales llamadas Fin r y Fin s , que sirven como marcas <strong>de</strong> fin <strong>de</strong><br />
98
archivo y que se insertan en la cola <strong>de</strong>spués <strong>de</strong> que se hayan generado todas las<br />
tuplas <strong>de</strong> r y <strong>de</strong> s (respectivamente). Para una evaluación eficaz, se <strong>de</strong>berían<br />
construir los índices apropiados en las r<strong>el</strong>aciones r y s. Según se aña<strong>de</strong>n las tuplas<br />
a ambas r<strong>el</strong>aciones se <strong>de</strong>ben mantener los índices actualizados.<br />
El algoritmo <strong>de</strong> join encauzado es <strong>el</strong> siguiente :<br />
hechor = falso;<br />
hechos = falso;<br />
r = ∅ ;<br />
s = ∅ ;<br />
resultado = ∅ ;<br />
mientras not hechor or not hechos<br />
si la cola está vacía entonces esperar hasta que la cola no este vacía;<br />
t = primera entrada <strong>de</strong> la cola;<br />
si t = Finr entonces<br />
sino<br />
fin si<br />
fin mientras<br />
hechor = verda<strong>de</strong>ro;<br />
si t = Fins entonces<br />
sino<br />
fin si<br />
hechos = verda<strong>de</strong>ro;<br />
si t es <strong>de</strong> la entrada r entonces<br />
sino<br />
fin si<br />
r = r U {t};<br />
resultado = resultado U ({t} s);<br />
s = s U {t};<br />
resultado = resultado U (r {t});<br />
Algoritmo 5-5 - Join encauzado.<br />
99
5.4.4. Transformación <strong>de</strong> expresiones r<strong>el</strong>acionales.<br />
100<br />
Hasta ahora se han estudiado algoritmos <strong>para</strong> evaluar extensiones <strong>de</strong><br />
operaciones <strong>de</strong>l álgebra r<strong>el</strong>acional y se han estimado sus costos. Dado que una<br />
consulta se pue<strong>de</strong> evaluar <strong>de</strong> distintas maneras y por lo tanto con distintos costos<br />
estimados, este apartado consi<strong>de</strong>rará formas alternativas y equivalentes a sus<br />
expresiones.<br />
5.4.4.1. Equivalencia <strong>de</strong> expresiones.<br />
Cada implementación <strong>de</strong> base <strong>de</strong> datos tiene su forma <strong>de</strong> representación<br />
interna <strong>de</strong> <strong>consultas</strong> in<strong>de</strong>pendientes <strong>de</strong>l <strong>lenguaje</strong> <strong>de</strong> <strong>consultas</strong> utilizado. La<br />
representación interna <strong>de</strong>be cumplir con la característica <strong>de</strong> ser r<strong>el</strong>acionalmente<br />
completo, es por eso que comúnmente los motores <strong>de</strong> BD <strong>el</strong>igen la<br />
representación <strong>de</strong>l álgebra r<strong>el</strong>acional en forma <strong>de</strong> árbol sintáctico abstracto <strong>para</strong><br />
su representación interna.<br />
Dada una expresión <strong>de</strong>l álgebra r<strong>el</strong>acional, es trabajo <strong>de</strong>l optimizador<br />
alcanzar un plan <strong>de</strong> evaluación que calcule <strong>el</strong> mismo resultado que la expresión<br />
dada pero <strong>de</strong> la manera menos costosa <strong>de</strong> generar. Para encontrar este plan <strong>de</strong><br />
evaluación <strong>el</strong> optimizador necesita generar planes alternativos que produzcan <strong>el</strong><br />
mismo resultado que la expresión dada y <strong>el</strong>egir <strong>el</strong> más económico <strong>de</strong> <strong>el</strong>los. <strong>para</strong><br />
implementar este paso <strong>el</strong> optimizador <strong>de</strong>be generar expresiones que sean<br />
equivalente a la expresión dada por medio <strong>de</strong>l uso <strong>de</strong> las reglas <strong>de</strong> equivalencia<br />
que se explican a continuación.
5.4.4.2. Reglas <strong>de</strong> equivalencia.<br />
101<br />
Una regla <strong>de</strong> equivalencia dice que las expresiones <strong>de</strong> dos formas son<br />
equivalentes, por lo tanto se pue<strong>de</strong> transformar una en la otra mientras se<br />
preserva la equivalencia. Se entien<strong>de</strong> como preservar la equivalencia al hecho <strong>de</strong><br />
que las r<strong>el</strong>aciones generadas por ambas expresiones tienen <strong>el</strong> mismo conjunto <strong>de</strong><br />
atributos y contienen <strong>el</strong> mismo conjunto <strong>de</strong> tuplas.<br />
Formalmente se dice que se representa una expresión en su forma<br />
canónica.<br />
La noción <strong>de</strong> forma canónica es central a muchos brazos <strong>de</strong> la matemática<br />
y otras disciplinas r<strong>el</strong>acionadas. Esta pue<strong>de</strong> ser <strong>de</strong>finida como sigue:<br />
Dado un conjunto <strong>de</strong> Q objetos (digamos <strong>consultas</strong>) y una noción <strong>de</strong><br />
equivalencias entre objetos (digamos, la noción <strong>de</strong> que q1 y q2 son equivalentes<br />
si y sólo si <strong>el</strong>las producen <strong>el</strong> mismo resultado), un subconjunto C <strong>de</strong> Q se dice la<br />
forma canónica <strong>de</strong> Q (bajo la <strong>de</strong>finición <strong>de</strong> equivalencia expuesta anteriormente) si<br />
y sólo si cada objeto q en Q es equivalente a sólo un objeto c en C. El objeto c es<br />
llamado la forma canónica <strong>de</strong> <strong>el</strong> objeto q. Todas las propieda<strong>de</strong>s <strong>de</strong> interés que se<br />
aplican al objeto q también se aplican a su forma canónica c; por lo tanto es<br />
suficiente estudiar sólo <strong>el</strong> pequeño conjunto <strong>de</strong> formas canónicas C y no <strong>el</strong><br />
conjunto Q con <strong>el</strong> fin <strong>de</strong> probar una variedad <strong>de</strong> resultados.<br />
las reglas <strong>de</strong> equivalencia <strong>para</strong> llevar la expresión r<strong>el</strong>acional a una<br />
equivalente son:
1. Cascada <strong>de</strong> proyecciones:<br />
Π<br />
2. Cascada <strong>de</strong> s<strong>el</strong>ecciones:<br />
L1<br />
3. Conmutación <strong>de</strong> s<strong>el</strong>ecciones:<br />
( Π L2<br />
(...( Π Ln ( E))...)) = Π L1(<br />
E)<br />
σ θ1<br />
∧ σ θ 2(<br />
E) = σ θ1(<br />
σ θ 2(<br />
E))<br />
σ θ1(<br />
σ θ 2(<br />
E)) = σ θ 2(<br />
σ θ1(<br />
E))<br />
4. Conmutación <strong>de</strong> s<strong>el</strong>ección y proyección.<br />
5. Conmutación <strong>de</strong>l Join.<br />
Π L θ E θ L<br />
( σ ( )) = σ ( Π ( E))<br />
E = E<br />
E<br />
E1 θ 2 2 θ<br />
1<br />
102
6. Asociatividad <strong>de</strong>l Join Natural.<br />
caso1.<br />
(E )<br />
1<br />
E = E (E 2 E 3)<br />
E2 3 1<br />
caso 2. θ 2 involucra sólo atributos <strong>de</strong> 2 E y E 3 .<br />
(E )<br />
1<br />
θ1 E2<br />
θ 2∧θ<br />
3 E 3 = E1<br />
θ1 ∧ θ 3 (E2<br />
7. Distributividad <strong>de</strong> la s<strong>el</strong>ección con respecto al join.<br />
E 2<br />
caso 1. θ 0 involucra sólo atributos <strong>de</strong> E 1.<br />
σ θ 0(E 1 θ E2 ) σ θ 0(<br />
E1)<br />
= θ E2<br />
θ 2 E3)<br />
103<br />
caso 2. θ 1 involucra sólo atributos <strong>de</strong> 1 E y θ 2 involucra sólo atributos <strong>de</strong><br />
σ θ1∧<br />
θ 2(<br />
E<br />
θ E2 ) θ1<br />
1<br />
= ( σ ( E )) ( ))<br />
8. Distributividad <strong>de</strong> la proyección con respecto al join.<br />
θ ( σ θ 2 E2<br />
Si 1 L y 2 L son los atributos <strong>de</strong> 1 E y E2 respectivamente.<br />
Π (E = ( Π ( E ))<br />
L1 UL<br />
2<br />
1<br />
θ E2 ) L1<br />
1<br />
θ<br />
( Π L2<br />
( E2<br />
))
9. Conmutatividad <strong>de</strong> la unión y la intersección.<br />
E U E = E U E<br />
1<br />
1<br />
2<br />
E I E = E I E<br />
La diferencia <strong>de</strong> conjuntos no es conmutativa.<br />
10. Asociatividad <strong>de</strong> la unión e intersección.<br />
1<br />
2<br />
2<br />
( E1<br />
U E2<br />
) U E3<br />
= E1<br />
U ( E2<br />
U E3)<br />
( E I E ) I E = E I ( E I E )<br />
3<br />
2<br />
2<br />
1<br />
1<br />
1<br />
2<br />
3<br />
104<br />
11. Distributividad <strong>de</strong> la s<strong>el</strong>ección con respecto a la unión, intersección y<br />
diferencia.<br />
σ ( E U E ) = σ ( E ) U σ ( E )<br />
θ<br />
1<br />
1<br />
1<br />
2<br />
σ ( E I E ) = σ ( E ) I σ ( E )<br />
θ<br />
2<br />
2<br />
1<br />
1<br />
σ ( E − E ) = σ ( E ) − σ ( E ) = σ ( E ) − E<br />
θ<br />
12. Distributividad <strong>de</strong> la proyección con respecto a la unión.<br />
Ejemplo:<br />
θ<br />
θ<br />
θ<br />
1<br />
∏ L ( E1 U E2<br />
) = ( ∏ L ( E2<br />
)) U ( ∏ L ( E1))<br />
Tabla 5-3 - Reglas <strong>de</strong> equivalencia <strong>para</strong> expresiones r<strong>el</strong>acionales.<br />
θ<br />
θ<br />
θ<br />
2<br />
2<br />
2<br />
θ<br />
1<br />
2
105<br />
Supóngase que lo que se <strong>de</strong>sea es notificar a todos los dueños <strong>de</strong><br />
vehículos <strong>de</strong>l año, que estén siendo conducidos por los choferes con menos<br />
experiencia (supóngase un año o menos); la expresión r<strong>el</strong>acional sería :<br />
Π σ (( Dueños Moviles ) Choferes )<br />
Dueño . nombre ( Moviles.<br />
año=<br />
2001∧Choferes.<br />
Fecha _ licencia _ <strong>de</strong>s<strong>de</strong>><br />
Fecha()<br />
−1_<br />
año<br />
Se pue<strong>de</strong> utilizar la regla 6.1 con <strong>el</strong> fin <strong>de</strong> asociar <strong>el</strong> Join.<br />
Π σ ( Dueños ( Moviles Choferes ))<br />
Dueño . nombre ( Moviles.<br />
año=<br />
2001∧Choferes.<br />
Fecha _ licencia _ <strong>de</strong>s<strong>de</strong>><br />
Fecha()<br />
−1_<br />
año<br />
Aplicando la regla 5 se pue<strong>de</strong> conmutar <strong>el</strong> Join.<br />
Π σ (( Moviles Choferes ) Dueños )<br />
Dueño . nombre ( Moviles.<br />
año=<br />
2001∧Choferes.<br />
Fecha _ licencia _ <strong>de</strong>s<strong>de</strong>><br />
Fecha()<br />
−1_<br />
año<br />
Luego se aplica la regla 7.1 con <strong>el</strong> fin <strong>de</strong> distribuir la s<strong>el</strong>ección sobre <strong>el</strong> join.<br />
Π σ ( Moviles Choferes )) Dueños )<br />
Dueño . nombre (( Moviles.<br />
año=<br />
2001∧Choferes.<br />
Fecha _ licencia _ <strong>de</strong>s<strong>de</strong>><br />
Fecha()<br />
−1_<br />
año<br />
Aplicando la regla 7.2 se obtiene :<br />
Π σ ( Moviles))<br />
σ ( Choferes)))<br />
Dueños<br />
)<br />
Dueño . nombre ((( año=<br />
2001<br />
( Fecha _ licencia _ <strong>de</strong>s<strong>de</strong>><br />
Fecha()<br />
−1_<br />
año
106<br />
Las siguientes figuras muestran la expresión inicial y la final en una<br />
estructura <strong>de</strong> árbol sintáctico.
107<br />
Así, los optimizadores generan <strong>de</strong> manera sistemática expresiones<br />
equivalentes a la consulta dada. El proceso se entien<strong>de</strong> como sigue: dada una<br />
expresión, se analiza cada subexpresión <strong>para</strong> saber si se pue<strong>de</strong> aplicar una regla<br />
<strong>de</strong> equivalencia. De ser así se genera una nueva expresión don<strong>de</strong> la subexpresión<br />
que concuerda con una regla <strong>de</strong> equivalencia se reemplaza por su equivalente.<br />
Este proceso continúa hasta que no se pue<strong>de</strong>n generar más expresiones nuevas.<br />
Una optimización en términos <strong>de</strong> espacio se pue<strong>de</strong> lograr como sigue. Si se<br />
genera una expresión E1 <strong>de</strong> una expresión E2 mediante una regla <strong>de</strong><br />
equivalencia, entonces E1 y E2 son equivalentes en su estructura y por lo tanto<br />
sus subexpresiones son idénticas. Las técnicas <strong>de</strong> representación <strong>de</strong> expresiones<br />
que permiten a ambas expresiones apuntar a la subexpresión compartida pue<strong>de</strong>n<br />
reducir <strong>el</strong> espacio <strong>de</strong> búsqueda significativamente.<br />
5.5. Or<strong>de</strong>nes <strong>de</strong> Join.<br />
En los sistemas <strong>de</strong> base <strong>de</strong> datos r<strong>el</strong>acionales tradicionales raramente se<br />
encuentra una consulta que involucre más <strong>de</strong> 5 tablas, <strong>de</strong> este modo, <strong>el</strong> cálculo <strong>de</strong><br />
un or<strong>de</strong>n <strong>de</strong> Join óptimo con <strong>el</strong> menor costo <strong>de</strong> evaluación por medio <strong>de</strong> una<br />
búsqueda exhaustiva es perfectamente posible. Sin embargo, cuando esta<br />
consulta involucra 8 o más tablas <strong>el</strong> problema no se pue<strong>de</strong> <strong>de</strong>terminar <strong>de</strong> esta<br />
forma. Por lo tanto lo que se espera son algoritmos que calculen la mejor<br />
aproximación a la solución. Estos algoritmos pue<strong>de</strong>n ser se<strong>para</strong>dos en dos clases.<br />
1. Heurísticas: Construyen un plan <strong>de</strong> evaluación paso a paso <strong>de</strong> acuerdo a<br />
ciertos criterios pre<strong>de</strong>finidos.
108<br />
2. Aleatorios: Realizan una especie <strong>de</strong> “caminata aleatoria” a través <strong>de</strong>l<br />
espacio <strong>de</strong> todas las posibles soluciones.<br />
Generalmente <strong>el</strong> espacio <strong>de</strong> soluciones se <strong>de</strong>fine como <strong>el</strong> conjunto <strong>de</strong> todos<br />
los árboles que calculan <strong>el</strong> resultado <strong>de</strong>l Join y que contienen cada r<strong>el</strong>ación base<br />
exactamente una vez. Las hojas <strong>de</strong> estos árboles consisten en las r<strong>el</strong>aciones<br />
base, mientras que los nodos internos correspon<strong>de</strong>n a los resultados <strong>de</strong> Join <strong>de</strong><br />
los correspondientes hijos. Dado que la operación Join es conmutativa y asociativa<br />
(ver equivalencia <strong>de</strong> expresiones algebraicas en la sección 5.4.4.1) <strong>el</strong> número <strong>de</strong><br />
posibles árboles <strong>de</strong> proceso se incrementa rápidamente a medida que se<br />
incrementa <strong>el</strong> número <strong>de</strong> r<strong>el</strong>aciones bases que participan en <strong>el</strong> Join. Existe un<br />
subconjunto <strong>de</strong> este espacio <strong>de</strong> soluciones, comúnmente llamado “árboles en<br />
profundidad por la izquierda” que ha sido <strong>de</strong> especial interés en los estudios <strong>de</strong><br />
optimizadores <strong>de</strong> <strong>consultas</strong> [Steinbrunn93].<br />
Árboles en profundidad por la izquierda.<br />
Este subconjunto <strong>de</strong> soluciones consiste en todos los árboles don<strong>de</strong> la<br />
r<strong>el</strong>ación interna <strong>de</strong> cada Join es una r<strong>el</strong>ación base. Para un número fijo <strong>de</strong><br />
r<strong>el</strong>aciones base, la especificación <strong>de</strong> profundidad por la izquierda no <strong>de</strong>ja ningún<br />
grado <strong>de</strong> libertad concerniente a la forma <strong>de</strong>l árbol, sin embargo, se sabe a ciencia<br />
cierta que existen n! formas <strong>de</strong> agrupar n r<strong>el</strong>aciones base en las hojas <strong>de</strong>l árbol<br />
[Steinbrunn93].<br />
Árboles <strong>de</strong> disposición General.<br />
La solución en este espacio no es restringida <strong>de</strong> ninguna manera, dado que<br />
la forma <strong>de</strong> todos los posibles árboles pue<strong>de</strong> ser arbitraria , la cardinalidad <strong>de</strong> este
109<br />
⎛2(<br />
n −1)<br />
⎞<br />
conjunto es mucho más alta: <strong>para</strong> n r<strong>el</strong>aciones base existen ⎜ ⎟(<br />
n −1)!<br />
⎝ n −1<br />
⎠<br />
soluciones diferentes.<br />
El problema <strong>de</strong> encontrar un buen or<strong>de</strong>n <strong>de</strong> anidamiento pue<strong>de</strong> ser<br />
abordado <strong>de</strong> diferentes formas:<br />
1. Algoritmos Determinísticos. Cada algoritmo en esta clase construye una<br />
solución paso a paso <strong>de</strong> una forma <strong>de</strong>terminística, ya sea aplicando<br />
heurísticas o por medio <strong>de</strong> una búsqueda exhaustiva.<br />
2. Algoritmos Aleatorios. Para estos algoritmos se <strong>de</strong>fine un conjunto <strong>de</strong><br />
movimientos.<br />
Estos movimientos constituyen un “margen” entre las diferentes soluciones<br />
<strong>de</strong>l espacio <strong>de</strong> soluciones. Dos soluciones son conectadas por un “margen”<br />
si y sólo si, <strong>el</strong>las pue<strong>de</strong>n ser transformadas una en la otra por medio <strong>de</strong> un<br />
sólo movimiento. Cada uno <strong>de</strong> estos algoritmos realizan una “caminata<br />
aleatoria” a lo largo <strong>de</strong> los “márgenes” <strong>de</strong> acuerdo a ciertas reglas,<br />
terminando ya sea si no existen más movimientos a realizar o si se ha<br />
excedido un lapso <strong>de</strong> tiempo pre<strong>de</strong>terminado. La mejor solución encontrada<br />
hasta ese momento es la solución <strong>el</strong>egida.<br />
3. Algoritmos Genéticos. Estos algoritmos hacen uso <strong>de</strong> la estrategia<br />
aleatoria, muy similar a la evolución biológica. La i<strong>de</strong>a básica es comenzar<br />
con una población base y generar <strong>de</strong>scen<strong>de</strong>ncia por medio <strong>de</strong> cruces<br />
aleatorios, <strong>el</strong> más “digno” <strong>de</strong> los miembros <strong>de</strong> la población (<strong>de</strong> acuerdo a<br />
una función <strong>de</strong> costo) sobrevive a la s<strong>el</strong>ección y la siguiente generación<br />
estará basada en él. El algoritmo terminará ya sea si no hay mayor
110<br />
perfeccionamiento o <strong>de</strong>spués <strong>de</strong> un <strong>de</strong>terminado número <strong>de</strong> generaciones.<br />
El miembro más digno <strong>de</strong> la población actual en <strong>el</strong> momento <strong>de</strong> terminar <strong>el</strong><br />
algoritmo será la solución <strong>el</strong>egida.<br />
4. Algoritmos híbridos. Los algoritmos híbridos combinan las estrategias <strong>de</strong> los<br />
algoritmos <strong>de</strong>terminísticos y <strong>de</strong> los aleatorios. La i<strong>de</strong>a es que la solución<br />
obtenida por medio <strong>de</strong> algoritmos <strong>de</strong>terminísticos sirva como punto <strong>de</strong><br />
partida <strong>para</strong> los algoritmos aleatorios o como población base <strong>para</strong> los<br />
algoritmos genéticos.<br />
5.5.1. Algoritmos Determinísticos.<br />
5.5.1.1. S<strong>el</strong>ectividad mínima.<br />
Las buenas soluciones comúnmente se caracteriza porque los resultados<br />
intermedios tienen una pequeña cardinalidad. La heurística <strong>de</strong> s<strong>el</strong>ectividad mínima<br />
construye un árbol <strong>de</strong> profundidad por la izquierda paso a paso mientras trata <strong>de</strong><br />
mantener r<strong>el</strong>aciones intermedias tan pequeñas como sea posible. El factor <strong>de</strong><br />
s<strong>el</strong>ectividad s <strong>de</strong> R1 R2 se <strong>de</strong>fine como:
111<br />
Al principio, <strong>el</strong> conjunto <strong>de</strong> r<strong>el</strong>aciones a ser unidas se divi<strong>de</strong>n en dos<br />
subconjuntos. El conjunto <strong>de</strong> r<strong>el</strong>aciones ya incorporados en <strong>el</strong> resultado intermedio<br />
<strong>de</strong>notado como Rusados y <strong>el</strong> conjunto <strong>de</strong> r<strong>el</strong>aciones que aun quedan por unir con <strong>el</strong><br />
resultado intermedio que se <strong>de</strong>nota como Rrestantes. Entonces, en cada paso <strong>de</strong> <strong>el</strong><br />
algoritmo la R<strong>el</strong>ación Ri ∈ Rrestantes con <strong>el</strong> menor factor <strong>de</strong> s<strong>el</strong>ectividad<br />
Rusados .<br />
será mezclada con <strong>el</strong> resultado intermedio y será movida <strong>de</strong>s<strong>de</strong> Rrestantes a<br />
5.5.1.2. Heurística Top-Down.<br />
El principio <strong>de</strong> esta técnica esta basado en la observación <strong>de</strong> que los<br />
últimos Join son los más importantes <strong>para</strong> la expresión en términos <strong>de</strong> costo,<br />
simplemente porque los resultados intermedios tien<strong>de</strong>n a ser algo más largos<br />
hacia <strong>el</strong> fin <strong>de</strong> la evaluación. Así, esta estrategia s<strong>el</strong>ecciona las r<strong>el</strong>aciones <strong>de</strong>l<br />
conjunto que pue<strong>de</strong>n ser mezcladas con menor costo con <strong>el</strong> resto <strong>de</strong> las<br />
r<strong>el</strong>aciones. Esta estrategia se aplicará repetidamente hasta que no que<strong>de</strong>n<br />
r<strong>el</strong>aciones disponibles.<br />
Ejemplo: suponiendo que existen 6 tablas (O, B, A, P, W, C) a ser unidas,<br />
la primera r<strong>el</strong>ación en <strong>el</strong> or<strong>de</strong>n será la que tiene <strong>el</strong> menor costo si se une con <strong>el</strong><br />
resto, suponiendo un costo h como medida mínima, <strong>el</strong> costo <strong>de</strong> cada una <strong>de</strong> las 6<br />
combinaciones sería:
C(OBAPW C) = h<br />
C(CBAPW O) = 35h<br />
C(COAPW B) = 5h<br />
C(COBPW A) = h<br />
C(COBAW P) = h<br />
C(COBAP W) = h<br />
112<br />
El costo <strong>para</strong> C, A, P y W es <strong>el</strong> mismo, por lo tanto se escogerá<br />
arbitrariamente C, las 5 alternativas restantes <strong>de</strong>l segundo paso son:<br />
C(BAPW O) = 7h<br />
C(OAPW B) = 5h<br />
C(OBPW A) = h<br />
C(OBAW P) = h<br />
C(OBAP W) = h<br />
Al escoger A como la siguiente r<strong>el</strong>ación, <strong>el</strong> tercer paso será:<br />
El cuarto paso luego <strong>de</strong> escoger P:<br />
C(BPW O) = 7h<br />
C(OPW B) = 5h<br />
C(OBW P) = h<br />
C(OBP W) = h<br />
C(BW O) = 7h<br />
C(OW B) = 5h<br />
C(OB W) = h
113<br />
Luego <strong>de</strong> escoger W como la cuarta r<strong>el</strong>ación en <strong>el</strong> or<strong>de</strong>n las alternativas<br />
restantes son:<br />
Así, <strong>el</strong> or<strong>de</strong>n final <strong>de</strong> Join es :<br />
C(B O) = 7h<br />
C(O B) = 5h<br />
((((O B) W ) P) A) C<br />
Con un costo total <strong>de</strong> : (5+1+1+1+1) = 9h<br />
5.5.2. Algoritmos Aleatorios.<br />
Los Algoritmos aleatorios ven soluciones como puntos en un espacio <strong>de</strong><br />
soluciones y conecta estos puntos por márgenes que se <strong>de</strong>finen como un conjunto<br />
<strong>de</strong> movimientos. Este tipo <strong>de</strong> algoritmos realizan una suerte <strong>de</strong> caminata aleatoria<br />
a través <strong>de</strong>l espacio <strong>de</strong> soluciones a lo largo <strong>de</strong> los márgenes <strong>de</strong>finidos como<br />
movimientos. El tipo <strong>de</strong> movimientos que son consi<strong>de</strong>rados <strong>de</strong>pen<strong>de</strong>rá mucho <strong>de</strong>l<br />
tipo <strong>de</strong> espacio <strong>de</strong> soluciones. Si lo que se <strong>de</strong>sea son árboles <strong>de</strong> profundidad por<br />
la izquierda, cada solución sólo se pue<strong>de</strong> representar por medio <strong>de</strong> una lista<br />
or<strong>de</strong>nada <strong>de</strong> r<strong>el</strong>aciones que participan en <strong>el</strong> Join.<br />
5.5.2.1. Caminata aleatoria.<br />
El algoritmo aleatorio más simple realiza una caminata a través <strong>de</strong>l espacio<br />
<strong>de</strong> soluciones empezando en un punto s<strong>el</strong>eccionado aleatoriamente. En cada
114<br />
paso <strong>de</strong>l algoritmo se realiza un movimiento aleatorio y si <strong>el</strong> nuevo punto<br />
constituye una mejor solución (en términos <strong>de</strong> la función <strong>de</strong> costo <strong>el</strong>egida) este se<br />
almacenará como <strong>el</strong> nuevo resultado. El algoritmo terminará <strong>de</strong>spués <strong>de</strong> un<br />
pre<strong>de</strong>terminado número <strong>de</strong> movimientos y la mejor solución encontrada hasta <strong>el</strong><br />
momento será la solución <strong>el</strong>egida como resultado. En principio, este algoritmo<br />
traza una muestra aleatoria <strong>de</strong>s<strong>de</strong> <strong>el</strong> conjunto <strong>de</strong> todas las soluciones posibles y<br />
entrega la mejor solución <strong>de</strong>s<strong>de</strong> esta muestra. El rendimiento <strong>de</strong> este algoritmo<br />
<strong>de</strong>pen<strong>de</strong> fuertemente <strong>de</strong>l factor <strong>de</strong> buenas / malas soluciones y <strong>de</strong>l tamaño <strong>de</strong> la<br />
muestra <strong>el</strong>egida. Sin embargo, es obvio que esta estrategia es una perdida <strong>de</strong><br />
recursos dado que sólo cubre una pequeña área en la proximidad <strong>de</strong>l punto <strong>de</strong><br />
partida y no se hace nunca un intento siquiera <strong>de</strong> encontrar un mínimo local.<br />
5.5.2.2. Mejora Iterativa.<br />
Un acercamiento más sofisticado es <strong>el</strong> algoritmo <strong>de</strong> mejora iterativa<br />
[Swami88]. Luego <strong>de</strong> s<strong>el</strong>eccionar una punto <strong>de</strong> partida aleatorio <strong>el</strong> algoritmo busca<br />
un punto <strong>de</strong> costo mínimo. comenzando en <strong>el</strong> punto <strong>de</strong> partida, se <strong>el</strong>ige al azar un<br />
vecindario próximo (esto es, puntos que puedan ser alcanzados por exactamente<br />
un movimiento), si <strong>el</strong> costo asociados a los vecinos es menor que <strong>el</strong> costo <strong>de</strong>l<br />
punto actual entonces <strong>el</strong> movimiento se lleva a cabo y se busca un nuevo vecino<br />
con un menor costo. Un punto se <strong>de</strong>finirá como mínimo local si no se han<br />
encontrado vecinos con menor costo <strong>de</strong>spués <strong>de</strong> un cierto número <strong>de</strong> intentos.<br />
Este procedimiento se repite hasta que se hayan procesado un número<br />
pre<strong>de</strong>terminado <strong>de</strong> puntos <strong>de</strong> partida o se haya excedido un límite <strong>de</strong> tiempo. El<br />
menor <strong>de</strong> los mínimos locales encontrados será <strong>el</strong> resultado.
5.5.2.3. Simulación <strong>de</strong> cocción.<br />
115<br />
El algoritmo <strong>de</strong> mejora iterativa sufre <strong>de</strong> un gran inconveniente: dado que<br />
los movimientos son aceptados sólo si mejoran <strong>el</strong> resultado obtenido hasta <strong>el</strong><br />
momento, es posible que aún con un alto número <strong>de</strong> puntos <strong>de</strong> partida <strong>el</strong> resultado<br />
final sea inaceptable. Este será <strong>el</strong> caso cuando <strong>el</strong> espacio <strong>de</strong> solución no muestra<br />
un mínimo global, sino que una gran número <strong>de</strong> mínimos locales <strong>de</strong> alto costo. En<br />
este caso <strong>el</strong> algoritmo pue<strong>de</strong> quedar fácilmente atrapado en uno <strong>de</strong> estos mínimos<br />
locales.<br />
El algoritmo <strong>de</strong> Simulación <strong>de</strong> cocción es un refinamiento <strong>de</strong> la Mejora<br />
Iterativa que quita esta restricción. En <strong>el</strong> algoritmo <strong>de</strong> Simulación <strong>de</strong> cocción se<br />
pue<strong>de</strong> efectuar un movimiento aún si los puntos <strong>de</strong>l vecindario son <strong>de</strong> costos altos.<br />
Así este algoritmo no queda tan fácilmente atrapado en mínimos locales como <strong>el</strong><br />
algoritmo <strong>de</strong> Mejora Iterativa.<br />
El nombre <strong>de</strong> este algoritmo viene <strong>de</strong>l estudio <strong>de</strong>l proceso <strong>de</strong> cocción <strong>de</strong> los<br />
cristales, en este proceso natural <strong>el</strong> sistema eventualmente alcanza un estado <strong>de</strong><br />
mínima energía que se r<strong>el</strong>aciona directamente con la temperatura que toman los<br />
cristales.<br />
La siguiente figura muestra este comportamiento. Mientras que <strong>el</strong> Algoritmo<br />
<strong>de</strong> Mejora Iterativa se <strong>de</strong>tiene en <strong>el</strong> primer mínimo local que encuentra, <strong>el</strong><br />
algoritmo <strong>de</strong> Simulación <strong>de</strong> cocción se salta la barrera <strong>de</strong> costo que se<strong>para</strong> este<br />
punto <strong>de</strong>l punto mínimo global, dado que este algoritmo siempre acepta<br />
movimientos que lleven a una estado <strong>de</strong> menor costo, mientras que los<br />
movimientos que incrementan <strong>el</strong> costo se aceptan con una probabilidad que<br />
<strong>de</strong>pen<strong>de</strong>rá <strong>de</strong> la temperatura y <strong>de</strong> la diferencia entre <strong>el</strong> estado <strong>de</strong> costo actual y <strong>el</strong><br />
nuevo.
Figura 5-1 - Comportamiento <strong>de</strong>l Algoritmo <strong>de</strong> Simulación <strong>de</strong> Cocción<br />
116<br />
En cualquier caso, <strong>el</strong> comportamiento exacto <strong>de</strong>l algoritmo está<br />
<strong>de</strong>terminado por parámetros tales como la temperatura inicial, los pasos <strong>de</strong><br />
reducción <strong>de</strong> temperatura y la condición <strong>de</strong> fin. La literatura al respecto presenta<br />
distintas variantes que no viene al caso estudiarlas acá. Para encontrar<br />
referencias se recomienda consultar [Steinbrunn93].
5.5.3. Algoritmos Genéticos.<br />
117<br />
Los Algoritmos genéticos están diseñados <strong>para</strong> simular <strong>el</strong> proceso natural<br />
<strong>de</strong> evolución. Al igual que en la naturaleza, don<strong>de</strong> <strong>el</strong> miembro más digno <strong>de</strong> una<br />
población es <strong>el</strong> que tiene la mayor probabilidad <strong>de</strong> sobrevivir y <strong>de</strong> heredar sus<br />
características a su <strong>de</strong>scen<strong>de</strong>ncia, los algoritmos genéticos propagan soluciones<br />
<strong>para</strong> un <strong>de</strong>terminado problema <strong>de</strong> generación en generación, combinándolos <strong>para</strong><br />
alcanzar mejoras. A continuación se presenta una breve terminología, <strong>para</strong> una<br />
compresión más <strong>de</strong>tallada se recomienda consultar [Steinbrunn93].<br />
Una <strong>de</strong> las características más importantes <strong>de</strong> los algoritmos genéticos es<br />
que trabajan sobre un conjunto <strong>de</strong> soluciones (población). Las soluciones son<br />
representadas como ca<strong>de</strong>nas <strong>de</strong> caracteres (cromosomas) compuestos <strong>de</strong><br />
caracteres (genes) que pue<strong>de</strong>n tomar diferentes valores. Por lo tanto <strong>el</strong> problema<br />
que soluciona un algoritmo genético tiene una solución representada como una<br />
ca<strong>de</strong>na <strong>de</strong> caracteres con una codificación apropiada.<br />
La “dignidad” <strong>de</strong> una solución se medirá <strong>de</strong> acuerdo a una función objetivo<br />
que <strong>de</strong>be ser minimizada o maximizada. Generalmente, en un algoritmo genético<br />
bien diseñado ya sea <strong>el</strong> índice <strong>de</strong> dignidad promedio como <strong>el</strong> <strong>de</strong> la mejor solución<br />
se <strong>de</strong>ben incrementar con cada nueva generación.
5.5.3.1. Algoritmo genético <strong>para</strong> la optimización <strong>de</strong> or<strong>de</strong>nes <strong>de</strong> Join.<br />
El principio <strong>de</strong> este algoritmo es <strong>el</strong> siguiente.<br />
118<br />
Primero, se genera una población aleatoria <strong>de</strong> ca<strong>de</strong>nas <strong>de</strong> caracteres, Esta<br />
será la generación “cero” <strong>de</strong> soluciones. Luego, cada generación se <strong>de</strong>termina<br />
como sigue.<br />
• Una fracción <strong>de</strong> los miembros más dignos <strong>de</strong> la población se propaga a la<br />
siguiente generación (Principio <strong>de</strong> s<strong>el</strong>ección).<br />
• Una fracción <strong>de</strong> los miembros más dignos <strong>de</strong> la población se combina<br />
generando <strong>de</strong>scen<strong>de</strong>ncia. (principio <strong>de</strong> combinación)<br />
• Una fracción <strong>de</strong> la población (no necesariamente la más digna) se altera <strong>de</strong><br />
forma aleatoria (Principio <strong>de</strong> Mutación)<br />
Estas fracciones son <strong>el</strong>egidas <strong>de</strong> modo que <strong>el</strong> número total <strong>de</strong> soluciones<br />
permanezca invariante.<br />
Este ciclo se itera hasta que la mejor solución en la población ha alcanzado<br />
la calidad <strong>de</strong>seada, se ha producido un número pre<strong>de</strong>terminado <strong>de</strong> generaciones<br />
o hasta que la mejora entre una generación y otra ha caído por <strong>de</strong>bajo <strong>de</strong> un cierto<br />
umbral pre<strong>de</strong>terminado.<br />
Antes <strong>de</strong> que se pueda aplicar un cierto algoritmo se <strong>de</strong>be <strong>el</strong>egir una<br />
codificación apropiada y una función objetivo. Para la optimización <strong>de</strong> or<strong>de</strong>nes <strong>de</strong><br />
join las soluciones son árboles ya sea <strong>de</strong> profundidad por la izquierda o <strong>de</strong>
119<br />
disposición general. La función objetivo es la evaluación <strong>de</strong> costo a ser<br />
minimizada.<br />
Una codificación <strong>para</strong> <strong>el</strong> caso <strong>de</strong> los árboles <strong>de</strong> profundidad por la izquierda<br />
pue<strong>de</strong> ser representada únicamente por medio <strong>de</strong> una lista or<strong>de</strong>nada <strong>de</strong> sus<br />
hojas.<br />
Por ejemplo:<br />
((((R1 R4) R3) R2) R5) produce la ca<strong>de</strong>na “14325”.<br />
Principio <strong>de</strong> S<strong>el</strong>ección.<br />
El operador <strong>de</strong> s<strong>el</strong>ección se utiliza <strong>para</strong> se<strong>para</strong>r buenas y malas soluciones<br />
<strong>de</strong> la población, la motivación <strong>de</strong> este ejercicio es <strong>el</strong> po<strong>de</strong>r remover <strong>de</strong>l espacio <strong>de</strong><br />
soluciones a las malas soluciones. En la Figura 5-2 se muestra un ejemplo <strong>de</strong><br />
s<strong>el</strong>ección. La población <strong>de</strong> muestra consiste <strong>de</strong> 4 soluciones, la función objetivo<br />
dice que <strong>el</strong> costo <strong>de</strong>be ser minimizado. El costo <strong>para</strong> cada una <strong>de</strong> la soluciones se<br />
lista en la tabla <strong>de</strong> la Figura 5-2. A cada solución se le asigna un sector en una<br />
ruleta <strong>de</strong> tamaño inversamente proporcional al costo. Al cabo <strong>de</strong> 4 vu<strong>el</strong>tas a la<br />
ruleta se obtienen los resultados que se muestran en la segunda tabla <strong>de</strong> la Figura<br />
5-2 don<strong>de</strong> la solución 4 se ha “extinguido <strong>de</strong>bido a falta <strong>de</strong> adaptación”.
Figura 5-2 - Ejemplo <strong>de</strong>l principio <strong>de</strong> s<strong>el</strong>ección <strong>para</strong> <strong>el</strong> algoritmo genético <strong>para</strong> la optimización <strong>de</strong> or<strong>de</strong>nes <strong>de</strong> Join<br />
120<br />
Este esquema se basa en <strong>el</strong> factor <strong>de</strong> “dignidad” <strong>de</strong> los miembros <strong>de</strong> la<br />
población. Mientras mejor se satisfaga la función objetivo más posibilida<strong>de</strong>s tiene<br />
en la ruleta.<br />
Principio <strong>de</strong> Combinación.<br />
El operador <strong>de</strong> combinación es un medio <strong>para</strong> combinar parcialmente las<br />
buenas soluciones con <strong>el</strong> fin <strong>de</strong> obtener un resultado superior. La realización <strong>de</strong><br />
una combinación <strong>de</strong>pen<strong>de</strong>rá fuertemente <strong>de</strong> la codificación escogida dado que, <strong>el</strong><br />
operador <strong>de</strong> combinación tiene que tener la certeza <strong>de</strong> que las características <strong>de</strong><br />
una codificación en particular no se han violado. Para <strong>el</strong> caso estándar <strong>de</strong> la
121<br />
codificación estudiada en los árboles <strong>de</strong> profundidad por la izquierda se utiliza <strong>el</strong><br />
operador <strong>de</strong> combinación llamado “Intercambio <strong>de</strong> subsecuencias”.<br />
Para cada uno <strong>de</strong> los dos padres se s<strong>el</strong>ecciona una subsecuencia aleatoria,<br />
esta secuencia se quita <strong>de</strong> la ca<strong>de</strong>na y <strong>el</strong> espacio <strong>de</strong>jado se reemplaza con los<br />
caracteres <strong>de</strong>l otro padre en or<strong>de</strong>n <strong>de</strong> proce<strong>de</strong>ncia.<br />
Figura 5-3 - Ejemplo <strong>de</strong>l principio <strong>de</strong> combinación <strong>para</strong> <strong>el</strong> algoritmo genético <strong>para</strong> la optimización <strong>de</strong> or<strong>de</strong>nes <strong>de</strong> Join<br />
En <strong>el</strong> ejemplo <strong>de</strong> la Figura 5-3 se s<strong>el</strong>ecciona la subsecuencia “532” <strong>de</strong> la<br />
ca<strong>de</strong>na “45321”, <strong>el</strong> primer caracter <strong>de</strong> su <strong>de</strong>scen<strong>de</strong>ncia permanece igual que su<br />
padre (4), <strong>el</strong> segundo caracter se toma <strong>de</strong>l primer caracter <strong>de</strong>l otro padre (3), <strong>el</strong><br />
segundo caracter <strong>de</strong>l otro padre no pue<strong>de</strong> se utilizado pues ya está presente (1),<br />
por lo tanto <strong>el</strong> tercer caracter <strong>de</strong> la <strong>de</strong>scen<strong>de</strong>ncia se sacará <strong>de</strong>l tercer caracter <strong>de</strong>l<br />
otro padre, continuando este proceso se llega a “43521”. El proceso <strong>de</strong> <strong>de</strong>terminar<br />
la segunda <strong>de</strong>scen<strong>de</strong>ncia <strong>de</strong> efectúa <strong>de</strong> igual forma.<br />
Principio <strong>de</strong> Mutación.<br />
El operador <strong>de</strong> mutación se utiliza <strong>para</strong> introducir características que no<br />
están presentes en ningún miembro <strong>de</strong> la población. La mutación se lleva a cabo<br />
por medio <strong>de</strong> la alteración aleatoria <strong>de</strong> una ca<strong>de</strong>na s<strong>el</strong>eccionada aleatoriamente.<br />
Una forma básica <strong>de</strong> mutación es <strong>el</strong> intercambio (swap) <strong>de</strong> 2 caracteres aleatorios<br />
<strong>de</strong>ntro <strong>de</strong> una ca<strong>de</strong>na.
122<br />
Debido al carácter <strong>de</strong> la mutación como algo poco <strong>de</strong>seado en un proceso<br />
evolutivo, este no <strong>de</strong>be ser aplicado sin control sobre una generación dado que<br />
pue<strong>de</strong> ser dañada severamente. Usualmente se realizan muy pocas mutaciones<br />
en una generación.
5.6. Elección <strong>de</strong> los planes <strong>de</strong> evaluación.<br />
123<br />
Un plan <strong>de</strong> evaluación <strong>de</strong>fine exactamente que algoritmo utilizar <strong>para</strong> cada<br />
operación y como coordinar la ejecución <strong>de</strong> las operaciones.<br />
La Figura 5-4 muestra un plan <strong>de</strong> evaluación <strong>para</strong> la expresión analizada en<br />
<strong>el</strong> ejemplo <strong>de</strong> la sección 5.4.4.2. Se hace la suposición respecto a algunos índices<br />
con <strong>el</strong> fin <strong>de</strong> lograr encauzamiento.<br />
Figura 5-4 - Un plan <strong>de</strong> evaluación <strong>de</strong> ejemplo
124<br />
Una forma <strong>de</strong> <strong>el</strong>egir los planes <strong>de</strong> evaluación es simplemente <strong>el</strong>egir <strong>para</strong><br />
cada operación <strong>el</strong> algoritmo más económico <strong>para</strong> luego <strong>el</strong>egir cualquier<br />
or<strong>de</strong>nación. Sin embargo, la <strong>el</strong>ección in<strong>de</strong>pendiente <strong>de</strong>l algoritmo más económico<br />
no es necesariamente la mejor <strong>el</strong>ección. Por ejemplo, en una operación <strong>de</strong> Join,<br />
bajo ciertas circunstancias pue<strong>de</strong> ser más costosa con <strong>el</strong> algoritmo <strong>de</strong> join por<br />
mezcla <strong>de</strong> lo que podría ser con un algoritmo <strong>de</strong> Join por asociación. Sin embargo,<br />
la primera alternativa pue<strong>de</strong> producir una salida or<strong>de</strong>nada que pue<strong>de</strong> ayudar a la<br />
evaluación <strong>de</strong> una operación posterior (como una <strong>el</strong>iminación <strong>de</strong> duplicados o la<br />
entrada <strong>para</strong> otro join por mezcla) por lo tanto, <strong>para</strong> <strong>el</strong>egir <strong>el</strong> mejor algoritmo<br />
genérico habrá que consi<strong>de</strong>rar incluso los algoritmos no óptimos <strong>de</strong> las<br />
operaciones individuales.<br />
Como en <strong>el</strong> caso <strong>de</strong> las expresiones equivalentes, se pue<strong>de</strong>n utilizar reglas<br />
parecidas <strong>para</strong> <strong>de</strong>finir los posibles algoritmos <strong>de</strong> una operación, incluyendo aquí<br />
las <strong>de</strong>cisiones <strong>de</strong> encauzamiento <strong>de</strong> esta operación con otra a evaluar.<br />
Existen 2 gran<strong>de</strong>s aproximaciones <strong>para</strong> <strong>el</strong>egir <strong>el</strong> mejor plan <strong>de</strong> evaluación<br />
<strong>de</strong> una consulta. La primera examina todos los planes y <strong>el</strong>ige <strong>el</strong> mejor basándose<br />
en <strong>el</strong> costo estimado. La segunda aproximación utiliza heurísticas.<br />
La mayoría <strong>de</strong> los optimizadores actuales incorporan <strong>el</strong>ementos <strong>de</strong> ambas<br />
aproximaciones en la <strong>el</strong>ección <strong>de</strong> los planes <strong>de</strong> ejecución.<br />
5.6.1. Heurísticas.<br />
Aunque sea <strong>para</strong>dojal, <strong>el</strong> mayor inconveniente <strong>de</strong> la optimización por costos<br />
es precisamente <strong>el</strong> cálculo <strong>de</strong>l costo, <strong>para</strong> aliviar este cálculo muchos
125<br />
optimizadores utilizan heurísticas que ayudan a reducir <strong>el</strong> número <strong>de</strong> <strong>el</strong>ecciones a<br />
realizar en la optimización por costos.<br />
Algunas <strong>de</strong> estas son utilizadas y aceptadas por la mayoría <strong>de</strong> los<br />
optimizadores, a <strong>de</strong>cir :<br />
• Realizar las s<strong>el</strong>ecciones tan pronto como sea posible. Un optimizador<br />
basado sólo en heurísticas <strong>de</strong>bería aplicar esta regla al pie <strong>de</strong> la letra. Sin<br />
embargo, un poco <strong>de</strong> estudio indica que existe la posibilidad <strong>de</strong> que <strong>el</strong> uso<br />
<strong>de</strong> esta regla no ayu<strong>de</strong> siempre a reducir <strong>el</strong> costo. Como ejemplo <strong>de</strong> lo<br />
anterior, considérese la expresión σ ( r | x | s)<br />
don<strong>de</strong> la condición θ se<br />
refiere solamente a los atributos <strong>de</strong> s. Supóngase a<strong>de</strong>más que r es<br />
extremadamente pequeño, y que existe un índice en los atributos <strong>de</strong> join,<br />
pero no en los atributos <strong>de</strong> θ . Claramente en ese ejemplo es mala i<strong>de</strong>a<br />
realizar lo antes posible la s<strong>el</strong>ección, puesto que al no existir índices en los<br />
atributos <strong>de</strong> θ aplicar la s<strong>el</strong>ección significaría recorrer todas las tuplas <strong>de</strong> s<br />
(full scan), siendo que es más barato realizar <strong>el</strong> join (por medio <strong>de</strong> los<br />
índices) y luego rechazar las tuplas que no cumplen la s<strong>el</strong>ección.<br />
• Realizar las proyecciones al principio. Esta heurística se ocupa<br />
comúnmente en <strong>el</strong> caso <strong>de</strong> que sea necesario generar una r<strong>el</strong>ación<br />
temporal, se reduce la cantidad <strong>de</strong> atributos a s<strong>el</strong>eccionar, lo que implica<br />
reducir <strong>el</strong> tamaño <strong>de</strong> estas r<strong>el</strong>aciones en gran medida.<br />
Una revisión <strong>de</strong> las reglas <strong>de</strong> equivalencia <strong>de</strong>l apartado 5.4.4.2 pue<strong>de</strong> llevar a la<br />
construcción <strong>de</strong> un algoritmo heurístico que reor<strong>de</strong>ne los componentes <strong>de</strong>l árbol<br />
sintáctico inicial con <strong>el</strong> fin <strong>de</strong> mejorar la ejecución <strong>de</strong> la consulta.<br />
1. Deshacer las s<strong>el</strong>ecciones conjuntivas en una serie <strong>de</strong> s<strong>el</strong>ecciones simples,<br />
basándose en la regla <strong>de</strong> equivalencia número 2 (ver apartado 5.4.4.2).<br />
θ
126<br />
2. Mover las operaciones <strong>de</strong> s<strong>el</strong>ección hacia abajo en <strong>el</strong> árbol <strong>de</strong> la consulta<br />
<strong>para</strong> una ejecución tan pronto como sea posible. Esto se hace posible<br />
aplicando las reglas <strong>de</strong> equivalencia 3, 7.1, 7.2 y 11 (ver apartado 5.4.4.2).<br />
3. Determinar que operaciones <strong>de</strong> s<strong>el</strong>ección y join producirán las r<strong>el</strong>aciones<br />
temporales más pequeñas. Utilizando la asociatividad <strong>de</strong>l join se reforma <strong>el</strong><br />
árbol <strong>de</strong> tal manera que las r<strong>el</strong>aciones <strong>de</strong> los nodos hojas con estas<br />
s<strong>el</strong>ecciones restrictivas se ejecuten primero. Este paso consi<strong>de</strong>ra la<br />
s<strong>el</strong>ectividad <strong>de</strong> una r<strong>el</strong>ación o <strong>de</strong> un join y tiene en cuenta la asociatividad<br />
<strong>de</strong> las operaciones binarias consi<strong>de</strong>radas en las reglas <strong>de</strong> equivalencia 6 y<br />
10 (ver apartado 5.4.4.2).<br />
4. Deshacer y mover tan abajo en <strong>el</strong> árbol como sea posible las listas <strong>de</strong><br />
atributos y proyecciones y crear nuevas proyecciones don<strong>de</strong> sea necesario<br />
(atributos <strong>de</strong> join). Este paso incorpora las reglas <strong>de</strong> equivalencia 3, 8 y 12<br />
(ver apartado 5.4.4.2).<br />
5. I<strong>de</strong>ntificar aqu<strong>el</strong>los subárboles cuyas operaciones se pue<strong>de</strong>n encauzar y<br />
ejecutarlas utilizando encauzamiento (ver apartado 5.4.2).<br />
En resumen : estas heurísticas reor<strong>de</strong>nan la representación inicial <strong>de</strong>l árbol <strong>de</strong> una<br />
consulta <strong>de</strong> tal modo que las operaciones que reducen <strong>el</strong> tamaño <strong>de</strong> los resultados<br />
intermedios se apliquen primero; las s<strong>el</strong>ecciones anticipadas reducen <strong>el</strong> tamaño<br />
<strong>de</strong> tuplas y las proyecciones reducen <strong>el</strong> número <strong>de</strong> atributos. Las transformaciones<br />
heurísticas también reestructuran <strong>el</strong> árbol <strong>para</strong> que las s<strong>el</strong>ecciones y los joins más<br />
restrictivos se realicen antes que otras operaciones similares.
127<br />
La optimización heurística también hace correspon<strong>de</strong>r la expresión <strong>de</strong> la<br />
consulta heurísticamente transformada con secuencias alternativas <strong>de</strong><br />
operaciones <strong>para</strong> producir un conjunto candidato <strong>de</strong> planes evaluación.<br />
Un plan <strong>de</strong> evaluación incluye no sólo las operaciones r<strong>el</strong>acionales a<br />
realizar, sino también los índices a utilizar, <strong>el</strong> or<strong>de</strong>n en que se acce<strong>de</strong>n las tuplas y<br />
<strong>el</strong> or<strong>de</strong>n en que se tienen que producir las operaciones.
128<br />
Capítulo 6. El Optimizador <strong>de</strong> Consultas <strong>de</strong> Sybase<br />
Adaptive Server Enterprise, un ejemplo práctico.<br />
6.1. Introducción.<br />
El optimizador <strong>de</strong> <strong>consultas</strong> <strong>de</strong> Sybase Adaptive Server Enterprise (ASE -<br />
llamado antiguamente SQL-Server) se basa en estimaciones <strong>de</strong> costos, <strong>el</strong> objetivo<br />
principal es, entonces, encontrar <strong>el</strong> camino <strong>de</strong> acceso más barato que minimice <strong>el</strong><br />
tiempo total <strong>de</strong> una consulta. Para alcanzar este objetivo, <strong>el</strong> optimizador <strong>de</strong><br />
<strong>consultas</strong> <strong>de</strong> ASE buscará caminos <strong>de</strong> acceso que:<br />
en:<br />
• Minimicen <strong>el</strong> acceso a páginas lógicas<br />
• Minimicen <strong>el</strong> acceso a páginas físicas.<br />
Los pasos que <strong>el</strong> optimizador ocupa <strong>para</strong> analizar una consulta son :<br />
1. Análisis sintáctico (Parser) <strong>de</strong> la consulta validando a<strong>de</strong>más las referencias<br />
<strong>de</strong> objetos.<br />
2. Optimización <strong>de</strong> la consulta y generación <strong>de</strong>l plan <strong>de</strong> la consulta.<br />
3. Compilación <strong>de</strong>l plan <strong>de</strong> la consulta.<br />
4. Ejecución <strong>de</strong>l plan y <strong>de</strong>volución <strong>de</strong>l resultado al usuario.<br />
Un estudio más <strong>de</strong>tallado sobre <strong>el</strong> paso 2 llevará a una subdivisión <strong>de</strong> este
1. Análisis <strong>de</strong> la consulta.<br />
2. S<strong>el</strong>ección <strong>de</strong> Índices.<br />
3. S<strong>el</strong>ección <strong>de</strong> los or<strong>de</strong>nes <strong>de</strong> Join.<br />
4. Uso <strong>de</strong> tablas temporales (Worktables).<br />
5. S<strong>el</strong>ección <strong>de</strong>l plan.<br />
6.2. Análisis <strong>de</strong> la Consulta.<br />
129<br />
El primer paso que realiza ASE es analizar cada tabla <strong>de</strong> la consulta con <strong>el</strong><br />
fin <strong>de</strong> reconocer los SARG (argumentos <strong>de</strong> búsqueda), las cláusulas OR y las<br />
cláusulas <strong>de</strong> JOIN. La i<strong>de</strong>ntificación <strong>de</strong> estas cláusulas sirve <strong>para</strong> que se utilicen<br />
en la siguiente etapa <strong>para</strong> s<strong>el</strong>eccionar índices.<br />
Cláusulas SARG : La existencia <strong>de</strong> SARG en una consulta habilita al optimizador<br />
a limitar <strong>el</strong> número <strong>de</strong> filas que satisfacen la consulta. El objetivo general es calzar<br />
un SARG con un índice <strong>para</strong> evitar un table scan. Los operadores validos <strong>de</strong> un<br />
SARG son =, >, =, y
130<br />
Se recomienda, siempre que se pueda, reescribir una consulta que tenga<br />
un operador <strong>de</strong> <strong>de</strong>sigualdad a una que contenga SARG. Por ejemplo, si se tiene la<br />
consulta<br />
SELECT NOMBRE FROM DUEÑO WHERE VIGENCIA 0<br />
Se pue<strong>de</strong> rescribir como :<br />
SELECT NOMBRE FROM DUEÑO WHERE VIGENCIA = 1<br />
La cual contiene un SARG valido que <strong>el</strong> optimizador reconocerá y lo<br />
consi<strong>de</strong>rará <strong>para</strong> calzarlo con algún índice.<br />
Algunas sentencias no se ven como SARG, sin embargo, pue<strong>de</strong>n ser<br />
transformadas a SARG por <strong>el</strong> optimizador, estas son :<br />
• BETWEEN se transforma en >= AND = ’01-01-2001’ AND FECHA = AND <<br />
NOMBRE LIKE “Sm%”
se transforma en:<br />
NOMBRE >= “Sm” AND NOMBRE
TABLA1.COLUMNA operador TABLE2.COLUMNA<br />
132<br />
Comúnmente un join involucra 2 tablas al menos que sea un Join recursivo<br />
(aunque en este caso se <strong>de</strong>be especificar la tabla 2 veces).<br />
Existen casos en que una subconsulta se pue<strong>de</strong> expresar como Join. En<br />
general ASE intentará transformar una subconsulta en un Join <strong>para</strong> permitirle al<br />
optimizador s<strong>el</strong>eccionar <strong>el</strong> or<strong>de</strong>n <strong>de</strong> Join más apropiado. Cuando ASE encuentra<br />
una subconsulta <strong>de</strong>l tipo IN, ANY o EXISTS tratará <strong>de</strong> transformarla en un tipo<br />
especial <strong>de</strong> Join <strong>de</strong>nominado Join <strong>de</strong> existencia. Un Join <strong>de</strong> existencia se pue<strong>de</strong><br />
optimizar <strong>de</strong> la misma forma que un Join Normal, excepto que <strong>para</strong> <strong>el</strong> caso <strong>de</strong> los<br />
Join <strong>de</strong> existencia, tan pronto como se cumpla <strong>el</strong> predicado <strong>de</strong> Join <strong>para</strong> la<br />
r<strong>el</strong>ación interna, <strong>el</strong> optimizador <strong>de</strong>tiene la búsqueda <strong>de</strong> valores coinci<strong>de</strong>ntes en la<br />
r<strong>el</strong>ación interna y <strong>de</strong>vu<strong>el</strong>ve un valor TRUE (verda<strong>de</strong>ro).<br />
Si ASE no pue<strong>de</strong> transformar la subconsulta en un Join <strong>de</strong> existencia, la<br />
consulta <strong>de</strong>be ser procesada <strong>de</strong>s<strong>de</strong> a<strong>de</strong>ntro hacia fuera, esto es, se <strong>de</strong>be ejecutar<br />
la subconsulta y luego efectuar <strong>el</strong> Join con la R<strong>el</strong>ación externa, se plantea como<br />
ejemplo la siguiente consulta extraída <strong>de</strong> la Base <strong>de</strong> datos <strong>de</strong> ejemplo PUBS2 <strong>de</strong><br />
ASE:<br />
s<strong>el</strong>ect pub_name<br />
from publishers<br />
where pub_id not in (<br />
s<strong>el</strong>ect pub_id<br />
from titles<br />
where type = 'business')
será procesada por <strong>el</strong> optimizador <strong>de</strong> ASE <strong>de</strong> la siguiente forma :<br />
s<strong>el</strong>ect p.pub_id,<br />
tmp_fi<strong>el</strong>d = t.pub_id<br />
into #worktable<br />
from publishers p,<br />
titles t<br />
where p.pub_id *= t.pub_id and<br />
t.type = 'business'<br />
s<strong>el</strong>ect pub_name<br />
from publishers p,<br />
#worktable w<br />
where p.pub_id = w.pub_id and<br />
tmp_fi<strong>el</strong>d = NULL<br />
drop table #worktable<br />
133<br />
Una subconsulta corr<strong>el</strong>acionada contiene una referencia a una tabla externa<br />
en la cláusula <strong>de</strong> join en la subconsulta, Por ejemplo, la subconsulta siguiente:<br />
s<strong>el</strong>ect col_a<br />
from table_1 t1<br />
where col_b = ( s<strong>el</strong>ect sum(col_x<br />
from table_2<br />
where col_y = t1.col_c)
134<br />
ASE procesará esta subconsulta <strong>de</strong>s<strong>de</strong> a<strong>de</strong>ntro hacia fuera usando una<br />
tabla intermedia al igual que en <strong>el</strong> ejemplo anterior, la consulta anterior quedará<br />
<strong>de</strong>la siguiente manera:<br />
s<strong>el</strong>ect t1.col_c,<br />
suma = sum(t2.col_x)<br />
into #worktable<br />
from table_1 t1,<br />
table_2 t2<br />
where t2.col_c = t1.col_c<br />
s<strong>el</strong>ect t1.col_a<br />
from table1 t1,<br />
#worktable w<br />
where t1.col_c w.col_c and<br />
t1.col_b = w.suma<br />
drop table #worktable<br />
Para <strong>el</strong> procesamiento <strong>de</strong> algunas sub<strong>consultas</strong> ASE usa un una porción<br />
<strong>de</strong>l caché <strong>de</strong> memoria que almacena los resultados <strong>para</strong> cada una <strong>de</strong> las<br />
ejecuciones subsecuentes <strong>de</strong> la subconsulta. Esto ayuda a mejorar <strong>el</strong> rendimiento<br />
cuando hay valores duplicados en las columnas <strong>de</strong> Join.
135<br />
Mientras se procesa la consulta, <strong>el</strong> optimizador evalúa la efectividad <strong>de</strong>l<br />
caché, si este índice se ve bajo, <strong>el</strong> optimizador <strong>de</strong>termina que <strong>el</strong> caché <strong>de</strong><br />
sub<strong>consultas</strong> es inútil y lo reduce en tamaño.<br />
6.3. S<strong>el</strong>ección <strong>de</strong> Índices.<br />
Una vez que la fase <strong>de</strong> análisis <strong>de</strong> la consulta se ha completado <strong>el</strong> próximo<br />
paso es hacer calzar las cláusulas i<strong>de</strong>ntificadas anteriormente con los índices<br />
disponibles en la base <strong>de</strong> datos y estimar los costos <strong>de</strong> entrada y salida. Al igual<br />
que en <strong>el</strong> caso <strong>de</strong> System R, <strong>el</strong> costo <strong>de</strong> cada uno <strong>de</strong> los caminos <strong>de</strong> accesos por<br />
índices se com<strong>para</strong>n entre <strong>el</strong>los y se com<strong>para</strong>n con <strong>el</strong> costo <strong>de</strong> un table scan con<br />
<strong>el</strong> fin <strong>de</strong> <strong>de</strong>terminar <strong>el</strong> menor <strong>de</strong> <strong>el</strong>los.<br />
Al igual que System R, Sybase usa las estadísticas <strong>de</strong> distribución <strong>de</strong> datos<br />
<strong>de</strong>l catálogo <strong>para</strong> estimar <strong>el</strong> costo <strong>de</strong> los caminos <strong>de</strong> acceso, en <strong>el</strong> caso <strong>de</strong> que no<br />
existan estadísticas Sybase también ocupa los “números mágicos”, estos números<br />
son:<br />
Operador Porcentaje estimado <strong>de</strong> filas<br />
= 10%<br />
BETWEEN, > y < 25%<br />
>, =,
136<br />
Si la consulta contiene una cláusula <strong>de</strong> Join ASE buscará los índices que<br />
calcen con los atributos <strong>de</strong> Join, <strong>para</strong> este caso utiliza las estadísticas <strong>de</strong> <strong>de</strong>nsidad<br />
<strong>de</strong> índices las cuales estiman <strong>el</strong> número <strong>de</strong> ocurrencias <strong>de</strong> un valor en un índice.<br />
Si esta estadística no está disponible <strong>el</strong> optimizador estima <strong>el</strong> número <strong>de</strong> filas<br />
coinci<strong>de</strong>ntes con la fórmula:<br />
1 / número <strong>de</strong> filas en la tablas con menos filas<br />
por ejemplo, si tenemos una tabla A <strong>de</strong> 1.000.000 <strong>de</strong> filas y una tabla B con<br />
5.000 filas, la s<strong>el</strong>ectividad <strong>de</strong>l Join será <strong>de</strong> 1 / 5.000 = 0,0002; así <strong>para</strong> cada fila <strong>de</strong><br />
la tabla B se <strong>de</strong>berían esperar 1.000.000 * 0,0002 = 200 filas coinci<strong>de</strong>ntes con la<br />
tabla A.<br />
Ahora bien, en <strong>el</strong> caso <strong>de</strong> haber índices en los atributos <strong>de</strong> Join, ASE<br />
estimará la <strong>de</strong>nsidad <strong>de</strong> un índice como <strong>el</strong> porcentaje <strong>de</strong> valores únicos en un<br />
índice, si se tienen 1.000 valores distintos en <strong>el</strong> índice <strong>de</strong> la tabla A, la <strong>de</strong>nsidad<br />
<strong>de</strong>l índice <strong>de</strong>bería ser : 1 / 1.000 = 0,001; usando este valor <strong>de</strong> <strong>de</strong>nsidad, <strong>para</strong><br />
cada fila <strong>de</strong> la tabla B se esperan 1.000.000 * 0,001 = 1000 filas coinci<strong>de</strong>ntes con<br />
la cláusula <strong>de</strong> join.<br />
A menos que se utilice una cláusula OR, ASE utilizará un solo índice por<br />
tabla <strong>para</strong> satisfacer la consulta, <strong>el</strong> índice <strong>el</strong>egido <strong>de</strong>be ser <strong>el</strong> que requiera <strong>el</strong><br />
menor número <strong>de</strong> E/S <strong>para</strong> resolver la consulta.<br />
Como se ha visto anteriormente, hay instancias don<strong>de</strong> un table scan pue<strong>de</strong><br />
ser la mejor estrategia <strong>para</strong> la recuperación <strong>de</strong> los datos.<br />
Para cualquier caso <strong>el</strong> cálculo <strong>de</strong> la estimación <strong>de</strong> E/S es <strong>el</strong> mismo que se<br />
explicó en la sección 5.3.1, este es, <strong>el</strong> número <strong>de</strong> paginas <strong>de</strong> la tabla <strong>para</strong> <strong>el</strong> caso
137<br />
<strong>de</strong> un table scan, valor que se rescata <strong>de</strong> la página OAM [Rankins96] (object<br />
allocation map) <strong>de</strong> la tabla.<br />
En <strong>el</strong> caso <strong>de</strong> que exista un índice en cluster <strong>el</strong> costo se estimará como <strong>el</strong><br />
número <strong>de</strong> niv<strong>el</strong>es <strong>de</strong>l índice más <strong>el</strong> número <strong>de</strong> páginas a recorrer; este último<br />
valor a su vez se <strong>de</strong>termina como <strong>el</strong> producto entre <strong>el</strong> número estimado <strong>de</strong> filas a<br />
recuperar y <strong>el</strong> número <strong>de</strong> filas por página.<br />
Para un índice que no sea en cluster, <strong>el</strong> costo se estima como:<br />
Número <strong>de</strong> niv<strong>el</strong>es <strong>de</strong>l índice +<br />
El número <strong>de</strong> página <strong>de</strong>l niv<strong>el</strong> <strong>de</strong> hojas +<br />
El número <strong>de</strong> filas estimadas a rescatar (peor caso)<br />
Para índices únicos y <strong>para</strong> equi-join <strong>el</strong> costo <strong>de</strong> E/S e estima como una<br />
página <strong>de</strong> datos más <strong>el</strong> número <strong>de</strong> niv<strong>el</strong>es <strong>de</strong> índices que se <strong>de</strong>ben recorrer <strong>para</strong><br />
acce<strong>de</strong>r a la página <strong>de</strong> datos.<br />
Adicionalmente ASE utiliza la técnica <strong>de</strong> “cubrimiento <strong>de</strong>l índice” (in<strong>de</strong>x<br />
covering) la cual usa <strong>el</strong> niv<strong>el</strong> <strong>de</strong> hojas <strong>de</strong>l índice normal (no en cluster) <strong>de</strong> la<br />
misma manera que lo hace con <strong>el</strong> niv<strong>el</strong> <strong>de</strong> hoja <strong>de</strong> los índices en cluster, siempre y<br />
cuando todos los atributos que se necesitan se encuentren en la <strong>de</strong>finición <strong>de</strong>l<br />
índice. De esta manera <strong>el</strong> optimizador no acce<strong>de</strong> a las páginas <strong>de</strong> datos dado que<br />
tiene todos lo necesario en las páginas <strong>de</strong> índices.<br />
6.4. S<strong>el</strong>ección <strong>de</strong> los or<strong>de</strong>nes <strong>de</strong> Join.
138<br />
El optimizador <strong>de</strong> <strong>consultas</strong> evalúa todos los posibles or<strong>de</strong>nes <strong>de</strong> join y <strong>para</strong><br />
cada or<strong>de</strong>n <strong>de</strong> join consi<strong>de</strong>rado estima <strong>el</strong> costo <strong>de</strong> las diferentes alternativas <strong>de</strong><br />
índices <strong>para</strong> cada una <strong>de</strong> las tablas que participan en <strong>el</strong> Join.<br />
En <strong>el</strong> caso <strong>de</strong> que no hayan índices útiles <strong>para</strong> la consulta en una o más <strong>de</strong><br />
las tablas involucradas en <strong>el</strong> join, ASE consi<strong>de</strong>rará aplicar la estrategia <strong>de</strong><br />
reformateo <strong>para</strong> resolver la consulta eficientemente.<br />
De aquí que, <strong>el</strong> plan <strong>de</strong> consulta más optimo <strong>para</strong> un join involucra <strong>el</strong>egir los<br />
mejores índices <strong>para</strong> cada tabla y <strong>el</strong> or<strong>de</strong>n más eficiente <strong>para</strong> procesar las tablas<br />
en <strong>el</strong> join.<br />
6.4.1. Determinación <strong>de</strong> los or<strong>de</strong>nes <strong>de</strong> Join.<br />
Dado que <strong>el</strong> optimizador <strong>de</strong> ASE se basa en costos, <strong>el</strong> or<strong>de</strong>n <strong>de</strong> las tablas<br />
en la cláusula FROM no dicta <strong>el</strong> or<strong>de</strong>n en <strong>el</strong> cual las tablas <strong>de</strong>ben ser procesadas.<br />
Cuando se procesa un Join, <strong>el</strong> optimizador evalúa todas las permutaciones<br />
razonables y estima <strong>el</strong> costo total <strong>de</strong> E/S en términos <strong>de</strong> tiempo <strong>de</strong> E/S.<br />
El plan que resulta producto <strong>de</strong> la estimación más baja <strong>de</strong> los tiempos <strong>de</strong><br />
E/S será <strong>el</strong> plan <strong>el</strong>egido.<br />
Para minimizar <strong>el</strong> número <strong>de</strong> permutaciones que <strong>de</strong>ben ser examinadas, <strong>el</strong><br />
optimizador <strong>de</strong>sintegra <strong>el</strong> join <strong>de</strong> más <strong>de</strong> 4 tablas en todos los posibles grupos <strong>de</strong><br />
4 con <strong>el</strong> fin <strong>de</strong> evaluar las permutaciones <strong>de</strong> Join <strong>de</strong>ntro <strong>de</strong> cada uno <strong>de</strong> estos<br />
grupos.
139<br />
Esta alternativa es una solución iterativa, que se repite hasta que se<br />
<strong>de</strong>terminen los or<strong>de</strong>nes <strong>de</strong> Join <strong>para</strong> todas las tablas. El propósito <strong>de</strong> este alcance<br />
es limitar <strong>el</strong> número <strong>de</strong> permutaciones que <strong>el</strong> optimizador tenga que consi<strong>de</strong>rar.<br />
El algoritmo usado por ASE <strong>para</strong> procesar los Joins <strong>de</strong> más <strong>de</strong> 4 tablas es<br />
como sigue:<br />
1. Agrupar las tablas en todos los posibles grupos <strong>de</strong> 4.<br />
2. Para cada uno <strong>de</strong> estos grupos estimar <strong>el</strong> costo <strong>de</strong> join <strong>para</strong> cada una <strong>de</strong><br />
las permutaciones (4! = 24).<br />
3. <strong>de</strong>terminar <strong>el</strong> grupo con la permutación <strong>de</strong> menor costo, la primera tabla <strong>de</strong><br />
esta permutación se <strong>de</strong>ja como la tabla más externa <strong>de</strong>l join y se extrae <strong>de</strong><br />
la lista <strong>de</strong> tablas.<br />
4. Repetir los pasos 1, 2, 3 <strong>para</strong> las tablas que quedan, hasta que que<strong>de</strong>n sólo<br />
4 tablas. Estas 4 tablas sirven <strong>de</strong> entrada <strong>para</strong> la ultima estimación <strong>de</strong> costo<br />
<strong>de</strong> Join.<br />
Ejemplo:<br />
Supóngase una consulta que involucre 6 tablas, sean estas tablas T1, T2,<br />
T3, T4, T5, T6; Agrupando estas 6 tablas en todos los posibles grupos <strong>de</strong> 4 se<br />
tendrán :<br />
T1T2T3T4<br />
⎛6<br />
⎞<br />
⎜ ⎟ = 15 grupos<br />
⎝4⎠<br />
T1T2T3T5 T1T2T3T6 T1T2T4T5 T1T2T4T6
T1T2T5T6 T1T3T4T5 T1T3T4T6 T1T3T5T6 T1T4T5T6<br />
T2T3T4T5 T2T3T4T6 T2T3T5T6 T2T4T5T6 T3T4T5T6<br />
140<br />
Para cada grupo <strong>de</strong> 4 encontrar la permutación con costo más bajo y tomar<br />
la primera tabla <strong>de</strong> esa permutación, extraerla <strong>de</strong> la lista <strong>de</strong> tablas y <strong>de</strong>jarla como<br />
la tabla más externa <strong>de</strong>l Join.<br />
Asumiendo que la mejor permutación es: T3T5T4T2, la tabla T3 será la<br />
tablas más externa. Las tablas que quedan son reagrupadas en todos los posibles<br />
grupos <strong>de</strong> 4, la cantidad <strong>de</strong> grupos resultantes es:<br />
⎛5<br />
⎞<br />
⎜ ⎟ = 5 grupos<br />
⎝4⎠<br />
T1T2T4T5 T1T2T4T6 T1T2T5T6 T1T4T5T6 T2T4T5T6<br />
Si la permutación <strong>de</strong> costo más bajo es T4T2T5T6; será entonces la tabla<br />
T4 la segunda tabla más externa en la consulta. De aquí en a<strong>de</strong>lante quedan 4<br />
tablas por lo tanto se encuentra la permutación con menor costo <strong>de</strong> estas,<br />
supóngase que esta permutación es T5T2T1T6, este or<strong>de</strong>n <strong>de</strong> Join se agrega a<br />
las 2 tablas extraídas anteriormente quedando <strong>el</strong> or<strong>de</strong>n <strong>de</strong> Join <strong>de</strong> la consulta<br />
como :<br />
T3 T4 T5 T2 T1 T6<br />
El número <strong>de</strong> permutaciones examinadas con este algoritmo pue<strong>de</strong> ser<br />
sustancialmente menor especialmente cuando <strong>el</strong> número <strong>de</strong> tablas en la consulta<br />
exce<strong>de</strong> las 8 tablas.
141<br />
El beneficio principal <strong>de</strong> este algoritmo es economizar tiempo <strong>de</strong> CPU en la<br />
i<strong>de</strong>ntificación <strong>de</strong>l mejor or<strong>de</strong>n <strong>de</strong> Join. El número resultante <strong>de</strong> combinaciones<br />
⎛ n!<br />
⎞<br />
examinadas con este alcance es la suma <strong>de</strong> ⎜ ⎟ <strong>para</strong> cada iteración.<br />
⎝ ( n − 4)!<br />
⎠<br />
Para este ejemplo <strong>el</strong> número <strong>de</strong> permutaciones consi<strong>de</strong>radas <strong>de</strong>bería ser:<br />
6!<br />
5 4!<br />
+ + = 360 + 120 + 24 = 504<br />
( 6 − 4)!<br />
( 5 − 4)!<br />
( 4 − 4)!<br />
Valor que es mucho menor que las 6! = 720 permutaciones.<br />
Esto representa, <strong>para</strong> este ejemplo, un ahorro <strong>de</strong> un 30%. En la medida que<br />
<strong>el</strong> número <strong>de</strong> tablas se incrementa <strong>el</strong> ahorro se hace cada vez más significativo<br />
como se muestra en la siguiente tabla:<br />
Número<br />
<strong>de</strong> Tablas<br />
N! Método<br />
Optimizado<br />
Ahorro<br />
6 720 504 30%<br />
7 5040 1344 73.3%<br />
8 40320 3024 92.5%<br />
9 362880 6048 98.3%<br />
10 3628800 11088 99.7%<br />
16 20922789888000 148512 99.999%<br />
6.4.2. Estimación <strong>de</strong> los costos.<br />
Para cada permutación estudiada <strong>el</strong> optimizador <strong>de</strong> ASE <strong>de</strong>be estimar <strong>el</strong><br />
costo <strong>de</strong> ese or<strong>de</strong>n <strong>de</strong> Join particular en términos <strong>de</strong> E/S total. Con propósitos <strong>de</strong><br />
com<strong>para</strong>ción, ASE estima <strong>el</strong> total <strong>de</strong> E/S lógicas por tabla y <strong>el</strong> número <strong>de</strong> E/S
142<br />
físicas por tabla, luego las suma y lo transforma en un estimado <strong>de</strong>l tiempo total<br />
transcurrido.<br />
ASE tasa una lectura lógica en 2 ms. (milisegundos) y una lectura física en<br />
18 ms. Por lo tanto la razón entre las lecturas lógicas y las físicas es <strong>de</strong> 1 a 9.<br />
Estos valores son físicos e in<strong>de</strong>pendientes <strong>de</strong> la plataforma en la cual se ejecuta <strong>el</strong><br />
motor.<br />
Ejemplos :<br />
Sea la siguiente consulta <strong>de</strong> la Base <strong>de</strong> Datos PUBS2 <strong>de</strong> ASE:<br />
S<strong>el</strong>ect *<br />
From titles t, titleauthor ta<br />
Where t.title_id = ta.title_id and ta.royaltyper < 50<br />
Se hacen las siguientes suposiciones.<br />
• 15.000 filas en titles (15 filas por página), 1.000 páginas.<br />
• 25.000 filas en titleauthor (50 filas por página), 500 páginas.<br />
• Las estadísticas <strong>de</strong>l Índice en cluster sobre <strong>el</strong> atributo royaltyper <strong>de</strong> la<br />
tabla titleauthor indican que <strong>el</strong> 20% <strong>de</strong> las filas cumplen con<br />
royaltyper < 50.<br />
• Hay suficiente tamaño en <strong>el</strong> caché <strong>para</strong> mantener ambas tablas en<br />
memoria.
Ejemplo 1: tabla titles como tabla externa, estudio sin índices.<br />
143<br />
Para la tabla externa hay un costo <strong>de</strong> 1.000 páginas <strong>para</strong> leer la tabla<br />
completa con un table scan, al usar bucles anidados se necesita leer la tabla<br />
titleautor por cada fila <strong>de</strong> la tabla author, como hay 15.000 filas en la tabla<br />
externa, ASE <strong>de</strong>berá recorrer 15.000 veces las 500 páginas <strong>de</strong> la tabla interna.<br />
El número total <strong>de</strong> E/S <strong>para</strong> esta consulta se estima como:<br />
1.000 + (15.000 * 500) = 7.501.000 E/S.<br />
Luego ASE calcula los costos r<strong>el</strong>ativos <strong>para</strong> cada permutación, <strong>el</strong> primer<br />
scan en la tabla titles realiza 1.000 lecturas lógicas y 1.000 lecturas físicas.<br />
Para la tabla titleauthor, como cabe enteramente en <strong>el</strong> caché sólo se<br />
necesitan 500 lecturas físicas y 15.000 lecturas lógicas <strong>para</strong> cada una <strong>de</strong> las<br />
iteraciones. Por lo tanto:<br />
(1.000 * 18 + 1.000 * 2) + 500 * 18 + 15.000 * 500 * 2 = 15.029.000 ms =<br />
15.029 segundos ≈ 4 horas.<br />
Ejemplo 2: tabla titleauthor como tabla externa, sin índices<br />
500 paginas <strong>de</strong>l table-scan <strong>de</strong> la tabla externa.<br />
Dado que existe un SARG en la tabla titleauthor y asumiendo que no<br />
hay índices y por lo tanto no hay información estadística, ASE asume que un 33%<br />
<strong>de</strong> las filas <strong>de</strong>berían calzar con <strong>el</strong> argumento <strong>de</strong> búsqueda. Así ASE estima que<br />
sólo se <strong>de</strong>berían realizar 8.250 iteraciones en la tabla titles (si una fila <strong>de</strong> la<br />
tabla titleuthor no cumple con <strong>el</strong> SARG no se <strong>de</strong>be efectuar la iteración <strong>para</strong> esa<br />
fila).
Por lo tanto <strong>el</strong> costo r<strong>el</strong>ativo <strong>de</strong> la consulta es:<br />
144<br />
(500 * 18 + 500 * 2) + 1.000 * 18 + 8.250 * 1.000 * 2 = 16.528.000 ms =<br />
16.528 segundos ≈ 4.5 horas.<br />
Ejemplo 3: tabla titleauthor como tabla externa, índice en cluster sobre <strong>el</strong><br />
campo titleauthor.royaltyper, índice único en cluster sobre <strong>el</strong> campo titles.title_id.<br />
Dada la información estadística que indica que sólo <strong>el</strong> 20% <strong>de</strong> las tuplas <strong>de</strong><br />
titleauthor cumplen con <strong>el</strong> SARG, entonces ASE estima que 25.000 * 0,2 =<br />
5.000 filas <strong>de</strong> la tabla titleauthor cumplen con <strong>el</strong> SARG. Como <strong>el</strong> índice en<br />
cluster permite búsquedas por rango, ASE sólo <strong>de</strong>berá recorrer las tuplas que<br />
cumplen con la condición, estas son 5.000 filas / 50 filas por página = 100 páginas.<br />
A<strong>de</strong>más, como hay un índice único en cluster en la tabla titles sólo una<br />
fila <strong>de</strong>be calzar con cada fila iterada <strong>de</strong> la tabla titleauthor, osea 5.000 filas. A<br />
15 filas por página se tienen 5.000 / 15 = 334 páginas <strong>de</strong> datos a acce<strong>de</strong>r en<br />
titles mientras se procesa la consulta. Cada búsqueda simple todavía cuesta 3<br />
accesos a disco más. Con esta información ASE estima que la consulta <strong>de</strong>bería<br />
costar:<br />
100 páginas en titleauthor + (5.000 filas en titleauthor * 3 páginas<br />
por búsqueda en titles) = 15.500<br />
100 lecturas físicas en titleauthor: 18 * 100 = 1.800 ms.<br />
100 lecturas lógicas en titleauthor: 2 * 100 = 200 ms.<br />
334 lecturas físicas en titles: 18 * 334 = 6.012 ms.<br />
15000 lecturas lógicas en titles: 2 * 15.000 = 30.000 ms.
Total = 38.012 ms. ≈ 38 segundos.<br />
6.4.3. Estrategia <strong>de</strong> Reformateo.<br />
145<br />
Como se vio en los ejemplos anteriores, <strong>el</strong> escenario <strong>de</strong> costo en <strong>el</strong> peor<br />
caso <strong>para</strong> un join es <strong>el</strong> que implementa un table-scan en ambas tablas, la fórmula<br />
<strong>de</strong> costo resultante es:<br />
número <strong>de</strong> paginas <strong>de</strong> la tabla externa +<br />
(número <strong>de</strong> filas <strong>de</strong> la tabla externa *<br />
número <strong>de</strong> paginas <strong>de</strong> la tabla interna)<br />
Ocasionalmente pue<strong>de</strong> resultar más barato construir un índice temporal en<br />
cluster en la tabla interna y utilizarlo <strong>para</strong> procesar la consulta que recorre<br />
repetidas veces la tabla. Cuando esto ocurre, ASE es copia <strong>el</strong> contenido <strong>de</strong> la<br />
tabla en una tabla temporal en la base <strong>de</strong> datos tempdb y crea un índice en<br />
cluster en la(s) columnas <strong>de</strong> join, luego utiliza este índice <strong>para</strong> recorrer la tabla y<br />
así sólo recuperar las filas que califican <strong>para</strong> con la condición <strong>de</strong> Join.<br />
El costo <strong>de</strong> aplicar la estrategia <strong>de</strong> reformateo es <strong>el</strong> costo <strong>de</strong> las E/S<br />
requeridas <strong>para</strong> crear la tabla temporal más <strong>el</strong> costo <strong>de</strong> crear <strong>el</strong> índice en <strong>el</strong>la.<br />
Sybase calcula esta fórmula como sigue:<br />
P2 + log2 P2 * P2; don<strong>de</strong> P2 es <strong>el</strong> número <strong>de</strong> páginas <strong>de</strong> la tabla interna.<br />
Esta estrategia no se usará a menos que <strong>el</strong> costo estimado sea menor que<br />
<strong>el</strong> costo <strong>de</strong> hacer un join con table scan en la tabla interna. El costo total <strong>de</strong><br />
procesar la consulta <strong>de</strong>bería ser <strong>el</strong> costo <strong>de</strong> reformateo más <strong>el</strong> número <strong>de</strong> páginas<br />
<strong>de</strong> la tabla externa (P1) más <strong>el</strong> número <strong>de</strong> filas <strong>de</strong> la tabla externa (R1)
146<br />
multiplicado por <strong>el</strong> número <strong>de</strong> scans en la tabla externa. La ecuación completa que<br />
estima <strong>el</strong> costo <strong>de</strong> E/S <strong>para</strong> una consulta utilizando la estrategia <strong>de</strong> reformateo<br />
sería:<br />
(P2 + log2 P2 * P2) + P1 + R1<br />
Como ejemplo, supóngase que se tiene una tabla externa <strong>de</strong> 300 filas y 200<br />
páginas y una tabla interna que consiste en 100 páginas, <strong>el</strong> costo <strong>de</strong> reformateo<br />
será entonces :<br />
(100 + log2 100 * 100) + 200 + 300 ≈ 1300 E/S.<br />
Mientras que <strong>el</strong> costo <strong>de</strong> procesar la consulta usando table scan sería<br />
200 + (300 * 100) = 30.200 E/S.<br />
El uso <strong>de</strong> la estrategia <strong>de</strong> reformateo por parte <strong>de</strong>l optimizador <strong>de</strong> ASE,<br />
indica al usuario que seguramente no tiene <strong>de</strong>finidos los índices apropiados <strong>para</strong><br />
las tablas. Es válido pensar que la estrategia <strong>de</strong> reformateo es más efectiva que<br />
un table scan, sin embargo, no es menos cierto que una buena <strong>de</strong>finición <strong>de</strong><br />
índices es mucho más apropiada y <strong>de</strong> mejor resultado.<br />
6.4.4. Outer Joins.<br />
La sintaxis <strong>de</strong> un outer join en ASE se <strong>de</strong>fine con un asterisco (*) en <strong>el</strong> lado<br />
<strong>de</strong> la cláusula <strong>de</strong> join don<strong>de</strong> se <strong>de</strong>sea que se incluyan todas las filas.
147<br />
Tal y como se ha explicado en la sección 5.3.3.7 un outer join indicara que<br />
todas las filas <strong>de</strong> la tabla <strong>de</strong>l lado <strong>de</strong>l * tienen que ser incluidas en <strong>el</strong> resultado sin<br />
importar si la fila calce o no con la cláusula <strong>de</strong> join.<br />
En estos casos la tabla <strong>de</strong>l lado <strong>de</strong>l asterisco será forzada a ser tratada<br />
como la tabla externa (outer) y por lo tanto <strong>para</strong> este tipo <strong>de</strong> join, ASE no evaluará<br />
un join <strong>de</strong> or<strong>de</strong>n inverso.<br />
6.5. Uso <strong>de</strong> tablas temporales.<br />
Cuando <strong>el</strong> optimizador encuentra cláusulas ORDER BY, GROUP BY y<br />
DISTINCT comúnmente <strong>de</strong>terminará la creación <strong>de</strong> tablas temporales<br />
(worktables). Dado que las tablas temporales producen un procesamiento<br />
adicional y consumo <strong>de</strong> E/S <strong>el</strong> optimizador <strong>de</strong>be <strong>de</strong>cidir si <strong>de</strong>be crear o no estas<br />
tablas.<br />
Para <strong>el</strong> caso <strong>de</strong> la cláusula GROUP BY, siempre se <strong>de</strong>be crear una tabla<br />
temporal <strong>para</strong> realizar <strong>el</strong> agrupamiento y guardar cualquier valor agregado que se<br />
está generando <strong>para</strong> cada uno <strong>de</strong> los grupos solicitados.<br />
Para <strong>el</strong> caso <strong>de</strong> la cláusula DISTINCT, y como esta cláusula se aplica a<br />
todos los atributos <strong>de</strong> una fila, se <strong>de</strong>be crear una tabla que or<strong>de</strong>ne los valores y<br />
<strong>el</strong>imine los duplicados. Si existe un índice único en la tabla y todos los atributos <strong>de</strong><br />
este índice se han incluidos en <strong>el</strong> SELECT, se evitará la creación <strong>de</strong> la tabla<br />
temporal dado que <strong>el</strong> índice único garantiza la que cada fila es distinta.<br />
Para <strong>el</strong> caso <strong>de</strong> la cláusula ORDER BY, la utilización <strong>de</strong> una tabla<br />
<strong>de</strong>pen<strong>de</strong>rá <strong>de</strong> los índices sobre la tabla.
148<br />
Considérese la situación en la cual existe un índice en cluster sobre una<br />
tabla, la cláusula ORDER BY especifica como mínimo la primera columna <strong>de</strong>l<br />
índice en cluster y no especifica columnas que no sean parte <strong>de</strong>l índice. En este<br />
caso no se requiere crear una tabla temporal dado que la consulta se pue<strong>de</strong><br />
resolver ya sea por la exploración <strong>de</strong>l índice en cluster o por medio <strong>de</strong> un table<br />
scan. Sin embargo, si existe un índice que no sea en cluster y que a<strong>de</strong>más fue<br />
utilizado <strong>para</strong> resolver la consulta, se requiere una tabla temporal que or<strong>de</strong>ne los<br />
datos extraídos por medio <strong>de</strong>l índice no en cluster.<br />
No se necesitará la creación <strong>de</strong> una tabla temporal si la cláusula ORDER<br />
BY especifica al menos la primera columna <strong>de</strong> un índice normal (no en cluster)<br />
don<strong>de</strong> no hay columnas que no sean parte <strong>de</strong>l índice, y a<strong>de</strong>más sea este <strong>el</strong> índice<br />
que se utiliza <strong>para</strong> satisfacer un SARG.<br />
Ejemplo: s<strong>el</strong>ect * from table where text like “texto%”<br />
or<strong>de</strong>r by text<br />
6.6. S<strong>el</strong>ección <strong>de</strong>l plan.<br />
La s<strong>el</strong>ección <strong>de</strong>l plan <strong>de</strong> ejecución <strong>de</strong> una consulta estará entonces<br />
<strong>de</strong>terminada por la solución que tenga <strong>el</strong> menor costo estimado <strong>para</strong> la consulta<br />
referenciada, dado que esta <strong>el</strong>ección se estima, hay veces en que <strong>el</strong> usuario<br />
pue<strong>de</strong> estar un tanto escéptico acerca <strong>de</strong> si es <strong>el</strong> plan <strong>el</strong>egido <strong>el</strong> más optimo <strong>para</strong><br />
la consulta. Se hace necesaria entonces, información técnica específica acerca <strong>de</strong>l<br />
plan <strong>de</strong> ejecución que ayu<strong>de</strong> al usuario a respon<strong>de</strong>r las siguiente preguntas.<br />
• ¿ Consi<strong>de</strong>ró <strong>el</strong> optimizador los índices que se <strong>de</strong>finieron <strong>para</strong> cada una<br />
<strong>de</strong> las tablas o está realizando un table scan ? ( punto 6.3)
• ¿ Se utilizan tablas temporales <strong>para</strong> procesar la consulta ? (punto 6.5)<br />
• ¿ Se aplicó la estrategia <strong>de</strong> reformateo si es <strong>el</strong> caso ? (punto 6.4.3)<br />
149<br />
• ¿ Cuales son los ór<strong>de</strong>nes <strong>de</strong> Join que utiliza <strong>el</strong> optimizador <strong>para</strong> resolver<br />
la consulta ? (punto 6.4)<br />
• ¿ Como son las estimaciones <strong>de</strong> costo con respecto a los costos<br />
originales?<br />
Con <strong>el</strong> fin <strong>de</strong> conocer las respuestas a estas preguntas ASE proporciona<br />
una herramienta llamada set showplan on que <strong>de</strong>vu<strong>el</strong>ve al cliente un <strong>de</strong>talle<br />
<strong>de</strong>l plan <strong>de</strong> ejecución <strong>el</strong>egido <strong>para</strong> resolver la consulta. El análisis <strong>de</strong> la<br />
información que entrega esta opción escapa al alcance <strong>de</strong> este trabajo, <strong>para</strong> un<br />
estudio más <strong>de</strong>tallado <strong>de</strong>l tema se recomienda leer [Rankins96].<br />
6.6.1. Potenciales problemas <strong>de</strong>l optimizador y sus soluciones.<br />
Luego <strong>de</strong> escribir la consulta y leer <strong>el</strong> plan <strong>de</strong> ejecución, es posible que <strong>el</strong><br />
usuario <strong>de</strong>termine que <strong>el</strong> optimizador no esté <strong>el</strong>igiendo <strong>el</strong> plan más óptimo. A<br />
continuación se <strong>de</strong>tallan los problemas más comunes que llevan al optimizador a<br />
<strong>el</strong>egir un plan <strong>de</strong> ejecución pobre en términos <strong>de</strong> eficacia.<br />
Estadísticas actualizadas. Uno <strong>de</strong> los problemas más comunes<br />
encontrados en ambientes <strong>de</strong> producción es que, ya sea, las estadísticas no están<br />
disponibles <strong>para</strong> los índices, o bien, están <strong>de</strong>sactualizadas. Se recomienda<br />
entonces actualizar las estadísticas y re-ejecutar la consulta.
150<br />
Cláusulas SARG. Revisar la existencia <strong>de</strong> cláusulas SARG <strong>de</strong>ntro <strong>de</strong>l<br />
WHERE. Fijar atención en operadores <strong>de</strong> <strong>de</strong>sigualdad, operaciones sobre<br />
columnas y expresiones constantes que no puedan ser evaluadas en <strong>el</strong> momento<br />
<strong>de</strong> la compilación <strong>de</strong> la consulta.<br />
Índices que cubren <strong>consultas</strong>. Si lo que se espera es una cobertura <strong>de</strong><br />
índice, chequear que todos los campos <strong>de</strong>l índice estén presentes en la consulta.<br />
La falta <strong>de</strong> uno <strong>de</strong> <strong>el</strong>los lleva a una recuperación <strong>de</strong> datos que involucra toda la<br />
fila.<br />
Estrategia <strong>de</strong> reformateo. Si se está efectuando una estrategia <strong>de</strong><br />
reformateo, significa que, ya sea no existen índices <strong>para</strong> la consulta, o la consulta<br />
contiene SARGSs no optimizados que no pue<strong>de</strong>n utilizar los índices disponibles.<br />
Se recomienda reevaluar la in<strong>de</strong>xación <strong>de</strong> tablas o rescribir la consulta <strong>de</strong> manera<br />
que utilice los índices disponibles.<br />
6.6.2. Mejoras propias <strong>de</strong>l optimizador <strong>de</strong> ASE.<br />
En cada versión que se lanza al mercado, los motores <strong>de</strong> base <strong>de</strong> datos<br />
tradicionales tien<strong>de</strong>n a mejorar las características <strong>de</strong> optimización <strong>de</strong> <strong>consultas</strong>, en<br />
<strong>el</strong> caso <strong>de</strong> ASE, estas mejorías tienen que ver con <strong>el</strong> manejo <strong>de</strong> memoria y con las<br />
estadísticas <strong>de</strong>l catálogo.<br />
Ya en la versión 11, una <strong>de</strong> las mejoras está en la habilidad <strong>de</strong> po<strong>de</strong>r<br />
particionar <strong>el</strong> caché <strong>de</strong> datos y asignar objetos a diferentes particiones <strong>de</strong>l caché.<br />
Otra mejora está en <strong>el</strong> hecho <strong>de</strong> realizar E/S <strong>de</strong> hasta 16 Kb. <strong>de</strong> tamaño (<strong>el</strong><br />
tamaño <strong>de</strong> un extent) y no en bloques <strong>de</strong> 2 Kb. (<strong>el</strong> tamaño <strong>de</strong> la página <strong>de</strong> datos<br />
<strong>de</strong> Sybase).
151<br />
Una lectura <strong>de</strong> datos en bloques <strong>de</strong> 16 Kb. pue<strong>de</strong> ayudar a mejorar <strong>el</strong><br />
rendimiento <strong>de</strong> las <strong>consultas</strong> que rescatan un alto número <strong>de</strong> paginas<br />
secuenciales <strong>de</strong> datos minimizando así <strong>el</strong> número <strong>de</strong> accesos a disco. Las<br />
<strong>consultas</strong> que se pue<strong>de</strong>n beneficiar con este tipo <strong>de</strong> estrategia son las <strong>consultas</strong><br />
<strong>de</strong>l tipo:<br />
• Table scan.<br />
• Consultas por rango que utilizan índices en cluster.<br />
• Consultas cubiertas por índices simples (no en cluster)<br />
Por lo tanto, si <strong>el</strong> caché que utiliza <strong>para</strong> leer la tabla o índice está<br />
configurado <strong>para</strong> lecturas largas, <strong>el</strong> optimizador tomará ventaja <strong>de</strong> esto e intentará<br />
realizar lecturas <strong>de</strong> este tipo.<br />
Otra característica <strong>de</strong> esta versión es la habilidad que tiene <strong>el</strong> optimizador<br />
<strong>de</strong> usar la llamada estrategia <strong>de</strong> fetch-and-discard <strong>para</strong> las páginas que se leen <strong>de</strong><br />
disco. Un caché <strong>de</strong> ASE se compone <strong>de</strong> dos ca<strong>de</strong>nas, <strong>el</strong> MRU(Most Recently<br />
Used - más recientemente usado) y LRU (Least Recently Used - menos<br />
recientemente usado), en versiones anteriores a la versión 11 <strong>de</strong> ASE la estrategia<br />
<strong>de</strong>l uso <strong>de</strong>l caché era <strong>de</strong>l tipo FIFO (first in- first out), lo que significaba que toda<br />
página cargada en <strong>el</strong> caché <strong>de</strong>bía recorrerlo completamente efectuando <strong>el</strong> mismo<br />
número <strong>de</strong> saltos antes <strong>de</strong> ser reemplazada. Esto muchas veces dañaba <strong>el</strong><br />
rendimiento, sobre todo cuando se <strong>de</strong>bía leer una tabla gran<strong>de</strong> y las paginas (que<br />
seguramente sólo se iban a utilizar una sola vez) quedaban en <strong>el</strong> caché,<br />
colocando a las paginas que si necesitaban estar frecuentemente en <strong>el</strong> caché al<br />
final <strong>de</strong>l LRU.<br />
La estrategia <strong>de</strong> fetch-and-discard le permite al optimizador <strong>de</strong>terminar si<br />
una consulta es <strong>de</strong>l tipo <strong>de</strong> <strong>consultas</strong> que lee los datos una sola vez y no los
152<br />
necesita nuevamente. Si la consulta es <strong>de</strong> este tipo, <strong>el</strong> optimizador colocará la<br />
página al final <strong>de</strong>l LRU, <strong>de</strong> manera que no “empuje” fuera <strong>de</strong>l caché a las paginas<br />
que <strong>de</strong>berían permanecer en él. La versión 12 <strong>de</strong> ASE a<strong>de</strong>más le permite al<br />
usuario <strong>de</strong>terminar que estrategia <strong>de</strong> reemplazo utilizar <strong>para</strong> cada una <strong>de</strong> las<br />
tablas que se consi<strong>de</strong>ran en un join.<br />
Las <strong>consultas</strong> con las cuales <strong>el</strong> optimizador <strong>de</strong> ASE le aplica la estrategia<br />
<strong>de</strong> fetch-and-discard son las <strong>consultas</strong> <strong>de</strong>l tipo:<br />
• Table scan<br />
• Consultas por rango que utilizan índices en cluster.<br />
• Consultas cubiertas por índices simples (no en cluster)<br />
• La tabla externa en un Join (sólo se requiere un scan <strong>para</strong> recorrerla)<br />
• La tabla interna <strong>de</strong> un join, si esta no cabe completamente en <strong>el</strong> cache.<br />
6.7. Resumen.<br />
A lo largo <strong>de</strong> los años, <strong>el</strong> optimizador <strong>de</strong> ASE ha sufrido continuas mejoras<br />
(al igual que la mayoría <strong>de</strong> los optimizadores <strong>para</strong> motores comerciales), en esta<br />
sección se ha verificado la correspon<strong>de</strong>ncia entre la teoría expuesta a lo largo <strong>de</strong>l<br />
capítulo Capítulo 5 y la implementación comercial <strong>de</strong> uno <strong>de</strong> los motores <strong>de</strong> base<br />
<strong>de</strong> datos más conocidos en la actualidad.<br />
Se <strong>de</strong>muestra a<strong>de</strong>más que en la mayoría <strong>de</strong> las oportunida<strong>de</strong>s <strong>el</strong><br />
optimizador toma la <strong>de</strong>cisión correcta, sin embargo, hay ocasiones en las que <strong>el</strong><br />
optimizador pue<strong>de</strong> tomar una mala <strong>de</strong>cisión <strong>de</strong>bido a una imprecisa o incompleta<br />
información en las estadísticas <strong>de</strong>l catálogo como también en algunas<br />
consi<strong>de</strong>raciones <strong>de</strong> cómo se escribe la consulta.
153<br />
Ahora bien, cuando existen sospechas acerca <strong>de</strong> la <strong>el</strong>ección <strong>de</strong>l plan, ASE<br />
(como los <strong>de</strong>más motores <strong>de</strong> base <strong>de</strong> datos comerciales) disponen <strong>de</strong><br />
herramientas que proporcionan información acerca <strong>de</strong> las <strong>de</strong>cisiones tomadas<br />
<strong>para</strong> la <strong>el</strong>ección <strong>de</strong>l plan más óptimo.
Resumen y Conclusiones.<br />
Resumen<br />
154<br />
El procesamiento <strong>de</strong> <strong>consultas</strong> tiene varias etapas a seguir <strong>para</strong> resolver<br />
una consulta SQL, las características <strong>de</strong>l mo<strong>de</strong>lo r<strong>el</strong>acional permiten que cada<br />
motor <strong>de</strong> base <strong>de</strong> datos <strong>el</strong>ija su propia representación que, comúnmente, resulta<br />
ser <strong>el</strong> álgebra r<strong>el</strong>acional. La optimización <strong>de</strong> <strong>consultas</strong> es, entonces, una <strong>de</strong> estas<br />
etapas (que por cierto otros mo<strong>de</strong>los <strong>de</strong> bases <strong>de</strong> datos no poseen).<br />
Existen distintos métodos <strong>para</strong> optimizar <strong>consultas</strong> r<strong>el</strong>acionales, sin<br />
embargo <strong>el</strong> enfoque <strong>de</strong> optimización basada en costos combinado con heurísticas<br />
que permitan reducir <strong>el</strong> espacio <strong>de</strong> búsqueda <strong>de</strong> la solución es <strong>el</strong> método<br />
mayormente utilizado por los motores <strong>de</strong> base <strong>de</strong> datos r<strong>el</strong>aciones <strong>de</strong> la<br />
actualidad, en todo caso, in<strong>de</strong>pendiente <strong>de</strong>l método <strong>el</strong>egido <strong>para</strong> optimizar la<br />
consulta, la salida <strong>de</strong> este proceso <strong>de</strong>be ser un plan <strong>de</strong> ejecución, <strong>el</strong> cual<br />
comúnmente es representado en su forma <strong>de</strong> árbol r<strong>el</strong>acional.<br />
La optimización <strong>de</strong> <strong>consultas</strong> en base a costos supone la utilización <strong>de</strong> una<br />
medida <strong>de</strong> costo que sea común a lo largo <strong>de</strong>l proceso, esta medida <strong>de</strong>be<br />
representar <strong>el</strong> criterio <strong>de</strong> minimización en la utilización <strong>de</strong> recursos <strong>de</strong>l sistema, la<br />
medida estándar <strong>para</strong> bases <strong>de</strong> datos r<strong>el</strong>acionales es usualmente la cantidad <strong>de</strong><br />
E/S (tanto <strong>de</strong> disco como <strong>de</strong> la memoria intermedia). Este enfoque estima un costo<br />
que estará <strong>de</strong>terminado por formulas pre<strong>de</strong>finidas y por la información <strong>de</strong>l catalogo<br />
inherente a la consulta. Sin embargo <strong>el</strong> optimizador no siempre escoge <strong>el</strong> plan<br />
más optimo, ya que una búsqueda exhaustiva <strong>de</strong> la estrategia óptima pue<strong>de</strong><br />
consumir <strong>de</strong>masiado tiempo <strong>de</strong> proceso. Se dice entonces que <strong>el</strong> optimizador<br />
escoge una estrategia “razonablemente eficiente”.
155<br />
El catálogo <strong>de</strong> la base <strong>de</strong> datos guarda información estadística <strong>de</strong> cada una<br />
<strong>de</strong> las r<strong>el</strong>aciones como también <strong>de</strong> los índices <strong>de</strong> cada una <strong>de</strong> la r<strong>el</strong>aciones, estas<br />
estadísticas permiten estimar los tamaños <strong>de</strong> los resultados <strong>de</strong> varias<br />
operaciones. Esta información es particularmente útil cuando se dispone <strong>de</strong><br />
índices <strong>para</strong> auxiliar <strong>el</strong> procesamiento <strong>de</strong> la consulta, sin embargo, la existencia <strong>de</strong><br />
estas estructuras influencia <strong>de</strong> manera significativa en la <strong>el</strong>ección <strong>de</strong>l plan <strong>de</strong><br />
ejecución <strong>de</strong> la consulta.<br />
Una mala administración <strong>de</strong> la información que contiene <strong>el</strong> catálogo<br />
conducirá inevitablemente a una <strong>de</strong>safortunada <strong>el</strong>ección <strong>de</strong>l plan <strong>de</strong> ejecución.<br />
Para ayudar a solucionar este problema existen varios enfoques que conjunta o<br />
se<strong>para</strong>damente pue<strong>de</strong>n asistir al optimizador en su <strong>el</strong>ección. Uno <strong>de</strong> estos<br />
consiste en la actualización automática <strong>de</strong> las estadísticas que algunos motores<br />
<strong>de</strong> base <strong>de</strong> datos incluyen como opción. Otro enfoque es la opción <strong>de</strong> guardar en<br />
<strong>el</strong> catálogo planes <strong>de</strong> ejecución precalculados que a<strong>de</strong>más le ahorran al motor <strong>el</strong><br />
tiempo <strong>de</strong> cálculo <strong>de</strong>l plan. Obviamente estos planes son vulnerables a ser<br />
invalidados si se producen cambios lógicos en <strong>el</strong> esquema <strong>de</strong> la base <strong>de</strong> datos o<br />
si hay un cambio en la distribución <strong>de</strong> los datos a ser recuperados.<br />
Uno <strong>de</strong> los primeros optimizadores <strong>de</strong> <strong>consultas</strong> y <strong>el</strong> que se conoce como<br />
base <strong>para</strong> la mayoría <strong>de</strong> los optimizadores tradicionales es <strong>el</strong> optimizador <strong>de</strong><br />
System R. System R es un optimizador basado en costos pero que utiliza<br />
heurísticas <strong>para</strong> <strong>de</strong>splazar s<strong>el</strong>ecciones y proyecciones hacia abajo en <strong>el</strong> árbol <strong>de</strong><br />
la consulta, la resolución <strong>de</strong> joins se realiza mediante <strong>el</strong> uso <strong>de</strong> árboles <strong>de</strong><br />
profundidad por la izquierda O(n!) lo que permite <strong>el</strong> uso <strong>de</strong> evaluaciones<br />
encauzadas cuando sea posible. La estimación <strong>de</strong> los caminos <strong>de</strong> acceso <strong>para</strong><br />
índices secundarios supone que se necesita un acceso a disco por cada tupla <strong>de</strong><br />
la r<strong>el</strong>ación lo que supone <strong>el</strong> peor caso. Es probable que la estimación sea precisa
156<br />
con tamaños <strong>de</strong> buffer pequeños, sin embargo con un buffer <strong>de</strong> mayor tamaño la<br />
página que contiene la tupla podria estar todavía en memoria.<br />
Las contribuciones <strong>de</strong>l optimizador <strong>de</strong> system R con respecto a otras<br />
investigaciones hechas hasta ese entonces se basan en un mejor<br />
aprovechamiento <strong>de</strong> las estadísticas <strong>de</strong>l catálogo, la inclusión <strong>de</strong> la utilización <strong>de</strong><br />
CPU en las fórmulas <strong>de</strong>l cálculo <strong>de</strong> costos y los métodos <strong>para</strong> <strong>de</strong>terminar or<strong>de</strong>nes<br />
<strong>de</strong> join. El concepto <strong>de</strong> “factor <strong>de</strong> s<strong>el</strong>ección” le permite al optimizador estimar<br />
cuantas tuplas satisfacen los predicados <strong>de</strong> antemano, <strong>el</strong> concepto <strong>de</strong> “interesting<br />
or<strong>de</strong>rs” agrega una importancia r<strong>el</strong>ativa al or<strong>de</strong>n en que se solicito la salida, por lo<br />
tanto agrega un niv<strong>el</strong> <strong>de</strong> importancia a todos aqu<strong>el</strong>los or<strong>de</strong>namientos que<br />
respondan al or<strong>de</strong>n solicitado permitiendo evitar (cuando sea posible) un<br />
reor<strong>de</strong>namiento <strong>de</strong>l resultado final.<br />
En General, la teoría expuesta en <strong>el</strong> capítulo Capítulo 5 valida las<br />
investigaciones hechas a partir <strong>de</strong> system R, planteando <strong>el</strong> proceso <strong>de</strong><br />
optimización <strong>de</strong> <strong>consultas</strong> como sigue.<br />
El primer paso <strong>de</strong> un optimizador <strong>de</strong> <strong>consultas</strong> es encontrar una expresión<br />
<strong>de</strong>l álgebra <strong>de</strong> r<strong>el</strong>aciones que sea equivalente a la expresión dada y cuyo costo<br />
estimado <strong>de</strong> ejecución sea menor. En <strong>el</strong> apartado 5.4.4.2 se presenta una lista <strong>de</strong><br />
equivalencia <strong>de</strong> expresiones que se pue<strong>de</strong>n utilizar <strong>para</strong> transformar una<br />
expresión en otra equivalente, se usan estas reglas <strong>para</strong> generar<br />
sistemáticamente todas las expresiones equivalentes <strong>de</strong> la consulta y luego <strong>el</strong>egir<br />
la más barata. Dado que generalmente esta evaluación se basa en costos, se<br />
presentan en <strong>el</strong> apartado 5.3.1, 5.3.2 y 5.3.3 distintos algoritmos <strong>para</strong> la s<strong>el</strong>ección<br />
<strong>de</strong> caminos <strong>de</strong> acceso a r<strong>el</strong>aciones simples, a joins y <strong>consultas</strong> complejas, estas<br />
medidas están <strong>de</strong>terminadas por la información que se tiene en <strong>el</strong> catálogo <strong>de</strong> la<br />
base <strong>de</strong> datos.
157<br />
Para <strong>el</strong> caso <strong>de</strong> <strong>consultas</strong> a r<strong>el</strong>aciones simples se utilizará entonces la<br />
evaluación <strong>de</strong> cada una <strong>de</strong> las expresiones equivalentes con su evaluación <strong>de</strong><br />
costos <strong>para</strong> <strong>el</strong>egir <strong>el</strong> plan <strong>de</strong> acceso a la consulta más barato.<br />
Para <strong>el</strong> caso <strong>de</strong> Joins es necesario incluir <strong>el</strong> cálculo <strong>de</strong> or<strong>de</strong>nes <strong>de</strong> join, que<br />
consi<strong>de</strong>rará or<strong>de</strong>namientos y encauzamientos en la medida <strong>de</strong> los posible. Dado<br />
que <strong>el</strong> cálculo <strong>de</strong> estos or<strong>de</strong>namientos pue<strong>de</strong> ser costoso mientras más r<strong>el</strong>aciones<br />
estén involucradas en un Join, se presenta en <strong>el</strong> apartado 5.5 distintas técnicas<br />
<strong>para</strong> <strong>el</strong> cálculo <strong>de</strong> estos or<strong>de</strong>namientos, estas técnicas comúnmente iterativas<br />
introducen distintas heurísticas <strong>para</strong> reducir <strong>el</strong> espacio <strong>de</strong> búsqueda <strong>de</strong> soluciones<br />
buscando mejorarlo en cada iteración.<br />
Bajo este alero <strong>de</strong> teoría, se presenta en <strong>el</strong> capítulo Capítulo 6 un ejemplo<br />
práctico <strong>de</strong> cómo un motor <strong>de</strong> base <strong>de</strong> datos r<strong>el</strong>acional comercial enfrenta estos<br />
problema en la actualidad.<br />
Conclusiones.<br />
El <strong>lenguaje</strong> <strong>de</strong> <strong>consultas</strong> SQL tiene la gran particularidad <strong>de</strong> que (a menos<br />
que se exprese directamente) le <strong>de</strong>ja la tarea la <strong>el</strong>ección <strong>de</strong> caminos <strong>de</strong> accesos y<br />
técnicas <strong>de</strong> recuperación <strong>de</strong> datos al motor <strong>de</strong> procesamiento <strong>de</strong> <strong>consultas</strong>. Al<br />
in<strong>de</strong>pendizar <strong>de</strong> esta tarea al usuario final, se hacen necesarios un conjunto <strong>de</strong><br />
técnicas que permitan asegurar al motor que los datos serán rescatados <strong>de</strong> la<br />
manera “más optima posible”. Este componente es <strong>el</strong> optimizador <strong>de</strong> <strong>consultas</strong>, <strong>el</strong><br />
cual se encarga <strong>de</strong> <strong>el</strong>egir <strong>el</strong> plan <strong>de</strong> evaluación más apropiado dada la información<br />
con la que cuenta <strong>de</strong> <strong>el</strong> catalogo y una serie <strong>de</strong> técnicas y algoritmos pre<strong>de</strong>finidos<br />
<strong>para</strong> estos efectos.
158<br />
Por muy importante que sea <strong>el</strong> la etapa <strong>de</strong> optimización en una consulta (y<br />
<strong>de</strong> hecho lo es), existen casos en que la búsqueda <strong>de</strong>l plan más optimo <strong>de</strong><br />
ejecución <strong>de</strong> una consulta pue<strong>de</strong> tomar mucho tiempo, <strong>para</strong> solucionar este<br />
problema, los optimizadores se apoyan en heurísticas, en técnicas <strong>de</strong> búsquedas<br />
aleatorias y en reglas pre<strong>de</strong>finidas, con <strong>el</strong> fin <strong>de</strong> que, no abarcando todo <strong>el</strong> espacio<br />
<strong>de</strong> búsqueda, se dé con una solución que sea “razonablemente aceptable”<br />
Existen distintos enfoques <strong>para</strong> optimizar una consulta, sin embargo, y a<br />
partir <strong>de</strong> conclusiones hechas por las investigaciones <strong>de</strong> system R, la mayoría <strong>de</strong><br />
los optimizadores han <strong>el</strong>egido <strong>el</strong> enfoque <strong>de</strong> optimización basada en costos como<br />
pre<strong>de</strong>terminada. La utilización <strong>de</strong> <strong>el</strong> enfoque <strong>de</strong> optimización basada en costos se<br />
fundamenta en la necesidad <strong>de</strong> contar con una medida que sea representativa <strong>de</strong>l<br />
criterio <strong>de</strong> minimización en la utilización <strong>de</strong> recursos <strong>de</strong>l sistema. Esta medida<br />
pue<strong>de</strong> no ser la misma, <strong>de</strong>pendiendo <strong>de</strong>l tipo <strong>de</strong> SGBD y <strong>de</strong> los avances<br />
tecnológicos que se han logrado con <strong>el</strong> pasar <strong>de</strong>l tiempo, por ejemplo, system R<br />
utilizaba como medida <strong>de</strong> costo una medida <strong>de</strong> peso entre costos <strong>de</strong> E/S y<br />
utilización <strong>de</strong>l uso <strong>de</strong> CPU, actualmente, existe una ten<strong>de</strong>ncia (cuestionable a mi<br />
parecer) a obviar <strong>el</strong> uso <strong>de</strong> CPU como medida representativa <strong>de</strong> costos, dado los<br />
avances tecnológicos en este campo.<br />
Una <strong>de</strong> las ventajas que se logra comprendiendo <strong>el</strong> proceso <strong>de</strong> optimización<br />
<strong>de</strong> <strong>consultas</strong> es la <strong>de</strong> enten<strong>de</strong>r que es lo que hace realmente un optimizador y con<br />
esto evitar la construcción <strong>de</strong> malas <strong>consultas</strong>.<br />
Sin Embargo, nada <strong>de</strong> esto cobra mucha importancia si <strong>el</strong> diseño <strong>de</strong> la base<br />
<strong>de</strong> datos es pobre, estudios indican que <strong>el</strong> 65% <strong>de</strong> los problemas <strong>de</strong> tunning en<br />
bases <strong>de</strong> datos en ambientes <strong>de</strong> producción es <strong>de</strong>bido a un pobre diseño <strong>de</strong> la<br />
base <strong>de</strong> datos. En estos casos, por mucho capacidad e hardware que se le<br />
agregue al sistema no se logrará un mayor índice <strong>de</strong> rendimiento en la base <strong>de</strong><br />
datos.
son:<br />
159<br />
Algunas consi<strong>de</strong>raciones que ayudan al buen diseño <strong>de</strong> una base <strong>de</strong> datos<br />
• Seguir los estándares <strong>de</strong> normalización <strong>de</strong> base <strong>de</strong> datos.<br />
• Tratar <strong>de</strong> maximizar <strong>el</strong> uso <strong>de</strong> índices en cluster<br />
• Tratar <strong>de</strong> reducir <strong>el</strong> número <strong>de</strong> índices secundarios (no en cluster)<br />
• Si existen <strong>consultas</strong> que involucren más <strong>de</strong> 4 tablas en un Join se<br />
recomienda <strong>de</strong>snormalizar algunas tablas.<br />
• Para tablas potencialmente gran<strong>de</strong>s se recomienda <strong>el</strong> particionamiento<br />
horizontal <strong>de</strong> tablas (varias tablas con la misma estructura original pero con<br />
datos distribuidos por cierto criterio pre<strong>de</strong>finido).
Bibliografía.<br />
[Bj<strong>el</strong>etich99]<br />
[Comer79]<br />
[Codd71]<br />
[Date98]<br />
[Ioannidis96]<br />
[Kline99]<br />
[Kruse84]<br />
[Lorie78]<br />
160<br />
S. Bj<strong>el</strong>etich, G. Mable, “Microsoft SQL Server 7 Al <strong>de</strong>scubierto”, Prentice<br />
Hall, Madrid 1999, Traducción <strong>de</strong> “Microsoft SQL Server 7.0 Unleashed”<br />
,SAMS 1999.<br />
D. Comer, "The Ubiquitous B-tree", ACM Computer Surveys, Volumen<br />
11, Número 2, Junio 1979, pp. 121-137.<br />
E. F. Codd, “R<strong>el</strong>ational completeness of data base sublanguages”. In<br />
Courant Computer Science Symposium on Data Base Systems, volumen<br />
6, paginas 65 -- 98. Prentice-Hall, Mayo 1971.<br />
C. Date, “Fifty Ways to Quote Your Query”, Miller Freeman Inc, USA<br />
1998.<br />
URL http://www.dbpd.com/vault/9807xtra.htm<br />
Y. Ioannidis, "Query Optimization", ACM Computing Surveys,<br />
symposium issue on the 50th Anniversary of ACM, Volumen 28, Número<br />
1, Marzo 1996, pp. 121-123.<br />
K. Kline, L. Gould, A. Zanevsky, “Transact-SQL Programming”, O’Reilly,<br />
USA 1999.<br />
R. L. Kruse, “Estructura <strong>de</strong> datos y diseño <strong>de</strong> programas”, Prentice Hall,<br />
Mexico 1988, traducción <strong>de</strong> “Data Structures and Program Design”,<br />
Prentice-Hall, 1984.<br />
R.A. Lorie, and J.F. Nilsson, “An Access Specification Language for a<br />
R<strong>el</strong>ational Data Base System”. IBM Research Report RJ2218, Abril,<br />
1978.
[McJones97]<br />
[Rankins96]<br />
[S<strong>el</strong>inger79]<br />
[Silberschatz97]<br />
[Steinbrunn93]<br />
[Swami88]<br />
[Sybase01]<br />
[Wong76]<br />
Paul McJones, SRC Technical Note 1997 – 018 “The 1995 SQL<br />
Reunión: People, Projects, and Politics”, Agosto 1997.<br />
R. Rankins, J. R. Garbus, D. Salomon, B. W. McEwan, “Sybase<br />
SQLServer 11 UNLEASHED”, SAMS 1996.<br />
161<br />
P. G. S<strong>el</strong>inger, , M. M. Astrahan, R. Chamberlain, R. A. Lorie, T. Price,<br />
"Access Path S<strong>el</strong>ection in a R<strong>el</strong>ational Database Management System”.<br />
Proce<strong>de</strong>nte <strong>de</strong> la conferencia “ACM SIGMOD Conference”, Junio, 1979.<br />
A. Silberschatz, H. F. Korth, S. Sudarshan, “Fundamentos <strong>de</strong> Bases <strong>de</strong><br />
datos – Tercera Edición”, McGraw – Hill, España 1998, Traducción <strong>de</strong><br />
“Database System Concepts”, McGraw – Hill, USA 1997.<br />
M. Steinbrunn and G. Moerkotte and A. Kemper,"Optimizing Join<br />
Or<strong>de</strong>rs", Passau, Alemania, "1993",<br />
URL<br />
http://citeseer.nj.nec.com/steinbrunn93optimizing.html<br />
A. Swami y A.Gupta. Optimization of large join queries. conferencia ACM<br />
SIGMOD <strong>de</strong> administración <strong>de</strong> datos, USA, 1988<br />
Sybase, “Performance and Tunning gui<strong>de</strong>: Volume 2 – Optimizing and<br />
Abstract Plans”, Sybase, USA 2001.<br />
E. Wong, K. Youssefi, Decomposition – “A Strategy for Query<br />
Processing. ACM Transactions on Database Systems”, 1,3 (Septiembre)<br />
1976.
Apéndices.<br />
A. Sintaxis <strong>de</strong> SQL<br />
A.1. Definiciones <strong>de</strong> datos en SQL<br />
162<br />
Las Sentencias <strong>de</strong>l <strong>lenguaje</strong> <strong>de</strong> <strong>de</strong>finición <strong>de</strong> datos (DDL) que posee SQL<br />
operan en base a tablas. Las Principales sentencias DDL son las siguientes:<br />
• CREATE TABLE<br />
• DROP TABLE<br />
• ALTER TABLE<br />
• CREATE INDEX<br />
• DROP INDEX<br />
Las sentencias antes mencionadas restringen la atención a los aspectos<br />
que son <strong>de</strong> directo interés <strong>para</strong> <strong>el</strong> usuario y no los aspectos que tienen que ver<br />
con <strong>el</strong> niv<strong>el</strong> interno <strong>de</strong>l sistema (tales <strong>de</strong>talles son <strong>de</strong> importancia <strong>para</strong> <strong>el</strong> DBA 15 ).<br />
Una tabla base se <strong>de</strong>fine en los sistemas r<strong>el</strong>acionales como una fila <strong>de</strong><br />
encabezados <strong>de</strong> columnas más cero o más filas con valores <strong>de</strong> datos. Esta tabla<br />
es creada usando la sentencia CREATE TABLE <strong>de</strong>l DDL <strong>de</strong> SQL. La fila <strong>de</strong><br />
encabezados <strong>de</strong> columna especifica una o más columnas asociadas cada una a<br />
sus respectivos tipos <strong>de</strong> datos. Cada fila <strong>de</strong> datos contiene exactamente un valor<br />
<strong>de</strong> dato <strong>para</strong> cada columna.<br />
15 DataBase Administrator . Administrador <strong>de</strong> la base <strong>de</strong> datos.
163<br />
No existe un or<strong>de</strong>n <strong>de</strong> filas, pero es posible imponer un or<strong>de</strong>n sobre <strong>el</strong>las.<br />
Las columnas están or<strong>de</strong>nadas <strong>de</strong> izquierda a <strong>de</strong>recha pero este or<strong>de</strong>n no es<br />
parte <strong>de</strong>l mo<strong>de</strong>lo r<strong>el</strong>acional. Las Tablas son autónomas e in<strong>de</strong>pendientes a<br />
diferencia <strong>de</strong> las vistas las cuales no existen en su propio espacio pero si se<br />
<strong>de</strong>rivan <strong>de</strong> una o más tablas.<br />
A.1.1. Comando CREATE TABLE<br />
El comando CREATE TABLE se usa <strong>para</strong> especificar una nueva r<strong>el</strong>ación<br />
por medio <strong>de</strong> un nombre y especificando cada uno <strong>de</strong> sus atributos. A cada<br />
atributo se le da un nombre, un tipo <strong>de</strong> datos (<strong>para</strong> especificar su dominio) y<br />
algunas constraints 16 sobre <strong>el</strong> atributo.<br />
La sintaxis <strong>de</strong>l comando es :<br />
CREATE TABLE nombre_<strong>de</strong>_tabla<br />
(<strong>de</strong>finicion_<strong>de</strong>_columna [,<strong>de</strong>finicion_<strong>de</strong>_columna ] ...)<br />
don<strong>de</strong> la <strong>de</strong>finición <strong>de</strong> columna es <strong>de</strong> la forma :<br />
nombre_<strong>de</strong>_columna tipo_<strong>de</strong>_dato [ NOT NULL ]<br />
Ejemplo :<br />
create table DUENOS<br />
(<br />
RUT INTEGER not null,<br />
NOMBRE CHAR(30) not null,<br />
TELEFONO CHAR(10) ,<br />
DIRECCION CHAR(50)<br />
);<br />
16 Una Constraint es una regla que se <strong>de</strong>be aplicar a un atributo <strong>de</strong> una tabla. Las<br />
constraints proveen un mecanismo rápido y eficiente <strong>para</strong> asegurar la integridad <strong>de</strong> la base <strong>de</strong><br />
datos sin importar los cambios que requiera <strong>el</strong> usuario.
A.1.1.1. Definición <strong>de</strong> NOT NULL (no nulo)<br />
164<br />
Puesto que SQL permite valores nulos como valores <strong>de</strong> atributos, una<br />
constraint NOT NULL pue<strong>de</strong> ser especificada en un atributo <strong>para</strong> indicar que no se<br />
permiten valores nulos <strong>para</strong> este atributo. En general NOT NULL <strong>de</strong>be ser<br />
especificado <strong>para</strong> los atributos que componen la llave primaria <strong>de</strong> cada r<strong>el</strong>ación.<br />
A.1.1.2. Tipos <strong>de</strong> datos SQL<br />
Los siguientes tipos <strong>de</strong> datos son los comúnmente soportados por <strong>el</strong><br />
estándar SQL.<br />
Datos Numéricos INTEGER Entero con signo <strong>de</strong> 31 bits<br />
SMALLINT Entero con signo <strong>de</strong> 15 bits<br />
DECIMAL(p,q) Número con signo <strong>de</strong> p dígitos, q <strong>de</strong>cimales<br />
FLOAT(p) Número <strong>de</strong> punto flotante, p bits <strong>de</strong> precisión<br />
Datos String CHAR(n) Ca<strong>de</strong>na <strong>de</strong> texto <strong>de</strong> largo fijo <strong>de</strong> n bytes<br />
VARCHAR(n) Ca<strong>de</strong>na <strong>de</strong> texto <strong>de</strong> largo variante, hasta los n bytes<br />
GRAPHIC(n) Ca<strong>de</strong>na <strong>de</strong> texto <strong>de</strong> largo fijo, n*2 bytes<br />
VARGRAPHIC(n<br />
)<br />
Datos <strong>de</strong> Fecha y Hora DATE Fecha (aaaammmdd)<br />
A.1.2. Comando DROP TABLE<br />
TIME Hora (hhmmss)<br />
Ca<strong>de</strong>na <strong>de</strong> texto <strong>de</strong> largo variante, hasta los n*2 bytes<br />
TIMESTAMP Combinación <strong>de</strong> fecha y hora<br />
Tabla A-1 - Tipos <strong>de</strong> datos <strong>de</strong> SQL<br />
El comando DROP TABLE se usa <strong>para</strong> <strong>el</strong>iminar una r<strong>el</strong>ación y su <strong>de</strong>finición<br />
<strong>de</strong> atributos como también borra <strong>de</strong>l catálogo la tupla r<strong>el</strong>acionada a esta.<br />
La sintaxis <strong>de</strong> la Instrucción es :
DROP TABLE nombre_<strong>de</strong>_tabla;<br />
Ejemplo :<br />
drop table DUENOS;<br />
A.1.3. Comando ALTER TABLE<br />
165<br />
El comando ALTER TABLE es usado <strong>para</strong> agregar un atributo a una <strong>de</strong> las<br />
tablas <strong>de</strong> la base <strong>de</strong> datos. A<strong>de</strong>más cambia las tuplas en <strong>el</strong> catalogo <strong>de</strong> sistema<br />
<strong>de</strong> la BD. El nuevo atributo tendrá <strong>el</strong> valor nulo (NULL) en todas la tuplas <strong>de</strong> la<br />
r<strong>el</strong>ación inmediatamente <strong>de</strong>spués <strong>de</strong> ejecutada la instrucción, puesto que no se<br />
permite la constraint NOT NULL. La sintaxis <strong>de</strong> este comando es :<br />
ALTER TABLE nombre_<strong>de</strong>_tabla<br />
ADD nombre_<strong>de</strong>_columna tipo_<strong>de</strong>_dato;<br />
Ejemplo:<br />
alter table DUENOS add VIGENCIA CHAR(1);<br />
A.1.4. Comando CREATE INDEX<br />
El Comando CREATE INDEX se usa <strong>para</strong> crear un índice. Cada índice<br />
tiene un nombre <strong>el</strong> cual será usado <strong>para</strong> borrarlo en caso <strong>de</strong> que no se necesite<br />
más. La sintaxis <strong>de</strong> este comando es la siguiente:<br />
CREATE [ UNIQUE ] INDEX nombre_<strong>de</strong>_indice<br />
ON nombre_<strong>de</strong>_tabla ( nombre_<strong>de</strong>_columna [or<strong>de</strong>n]<br />
[,nombre_<strong>de</strong>_columna [or<strong>de</strong>n] ] ... )<br />
[CLUSTER];
166<br />
CLUSTER: La especificación opcional CLUSTER 17 en un comando CREATE INDEX indica<br />
si este índice estará <strong>el</strong> cluster. Una tabla dada pue<strong>de</strong> tener un sólo índice<br />
en cluster en un momento dado.<br />
ORDER: Toda especificación ORDER en una sentencia SQL CREATE INDEX <strong>de</strong>be ser<br />
ya sea ASC (ascen<strong>de</strong>nte) o DESC (<strong>de</strong>scen<strong>de</strong>nte) y por lo tanto especifica <strong>el</strong><br />
or<strong>de</strong>n en que se organizarán los datos, <strong>el</strong> valor por <strong>de</strong>fecto <strong>para</strong> ORDER es<br />
ASC.<br />
UNIQUE: La opción UNIQUE en una sentencia SQL CREATE INDEX especifica que no<br />
se permitirán dos registros en la tabla a in<strong>de</strong>xar que tengan <strong>el</strong> mismo valor<br />
<strong>para</strong> <strong>el</strong> campo (o la combinación <strong>de</strong> estos) <strong>para</strong> <strong>el</strong> cual se está creando <strong>el</strong><br />
índice.<br />
Ejemplo:<br />
create unique in<strong>de</strong>x DUENO_PK on DUENOS (RUT asc);<br />
A.1.5. Comando DROP INDEX<br />
El comando SQL DROP INDEX se usa <strong>para</strong> soltar <strong>el</strong> índice <strong>de</strong> la tabla<br />
r<strong>el</strong>acionada y borrar la tupla correspondiente <strong>de</strong>s<strong>de</strong> <strong>el</strong> catalogo <strong>de</strong> sistema <strong>de</strong> la<br />
base <strong>de</strong> datos. Una razón <strong>para</strong> borrar índices es que es costoso mantenerlos cada<br />
vez que la r<strong>el</strong>ación base es actualizada y por lo tanto se requiere espacio<br />
adicional. Los índices que especifican una constraint <strong>de</strong> llave (primaria, alterna o<br />
externa) no se pue<strong>de</strong>n borrar a menos que se quiera borrar también la constraint<br />
asociada. La sintaxis <strong>de</strong> la cláusula DROP INDEX es:<br />
DROP INDEX nombre_<strong>de</strong>_indice;<br />
Ejemplo:<br />
drop in<strong>de</strong>x DUENO_PK;<br />
17 La técnica <strong>de</strong> clustering involucra <strong>el</strong> tratar <strong>de</strong> almacenar en disco lo más cerca posible<br />
los registros que están r<strong>el</strong>acionados lógicamente, <strong>de</strong> manera <strong>de</strong> po<strong>de</strong>r mejorar <strong>el</strong> rendimiento.
A.2. Manipulación <strong>de</strong> datos en SQL<br />
SQL provee cuatro sentencias <strong>de</strong> manipulación <strong>de</strong> datos (DML). Esas son:<br />
• SELECT<br />
• UPDATE<br />
• DELETE<br />
• INSERT<br />
A.2.1. Comando SELECT<br />
167<br />
El comando DML SELECT es la sentencia SQL básica <strong>para</strong> la recuperación<br />
<strong>de</strong> información <strong>de</strong>s<strong>de</strong> una base <strong>de</strong> datos. (nótese que <strong>el</strong> comando SELECT <strong>de</strong><br />
SQL no guarda r<strong>el</strong>ación con <strong>el</strong> operador <strong>de</strong> s<strong>el</strong>ección <strong>de</strong>l álgebra r<strong>el</strong>acional). La<br />
sintaxis <strong>de</strong>l comando es la siguiente:<br />
SELECT [DISTINCT] ítem(s)<br />
FROM tabla(s)<br />
[ WHERE condición ]<br />
[ GROUP BY campo(s) ]<br />
[ HAVING condición ]<br />
[ ORDER BY campos]<br />
[ UNION SQL_SELECT]
168<br />
La palabra clave DISTINCT se usa <strong>para</strong> indicar que los valores duplicados o<br />
redundantes <strong>de</strong>ben ser <strong>el</strong>iminados antes que la función sea ejecutada. DISTINCT<br />
pue<strong>de</strong> ser especificada con las funciones agregadas COUNT y AVG pero es<br />
totalmente irr<strong>el</strong>evante <strong>para</strong> las funciones MAX y MIN. No se pue<strong>de</strong> usar esta<br />
cláusula junto con la función especial COUNT(*). La palabra Clave UNIQUE es un<br />
sinónimo <strong>para</strong> DISTINCT y las dos se pue<strong>de</strong>n usar sin distinción.<br />
Ejemplo:<br />
s<strong>el</strong>ect COUNT(DISCTINCT MARCA)<br />
FROM MOVIL;<br />
Retorna <strong>el</strong> número <strong>de</strong> Marcas <strong>de</strong> autos que tiene la empresa<br />
A.2.1.1. Funciones Agregadas <strong>de</strong> la cláusula SELECT<br />
SQL provee algunas funciones especiales que pue<strong>de</strong>n ser usadas con <strong>el</strong><br />
comando SELECT. Esas funciones son las siguientes:<br />
• COUNT<br />
• SUM<br />
• AVG<br />
• MAX<br />
• MIN<br />
• COUNT(*)<br />
COUNT : La función COUNT se usa <strong>para</strong> obtener <strong>el</strong> número <strong>de</strong> valores en la columna. Opera<br />
sobre una colección <strong>de</strong> valores en una columna <strong>de</strong> la tabla. La palabra clave
169<br />
DISTINCT se pue<strong>de</strong> usar conjuntamente con COUNT. Si <strong>el</strong> resultado <strong>de</strong>l argumento es<br />
<strong>el</strong> conjunto vacío la función COUNT retorna <strong>el</strong> valor cero. Un ejemplo <strong>de</strong> COUNT es:<br />
SELECT COUNT (DISTINCT MARCA)<br />
FROM MOVIL;<br />
SUM : La función SUM se usa <strong>para</strong> sumar los valores <strong>de</strong> una columna. La función opera sobre<br />
una colección <strong>de</strong> valores en una columna <strong>de</strong> la tabla. Los valores <strong>de</strong>ben ser numéricos.<br />
Si <strong>el</strong> resultado <strong>de</strong>l argumento es <strong>el</strong> conjunto vacío, SUM retorna NULL. Un ejemplo <strong>de</strong><br />
SUM es:<br />
SELECT SUM (HORA_HASTA - HORA_DESDE)<br />
FROM VIAJE<br />
WHERE PATENTE_MOVIL = 'HL-8483';<br />
AVG : La Función AVG se usa <strong>para</strong> promediar todos los valores s<strong>el</strong>eccionados en una columna,<br />
opera sobre una colección <strong>de</strong> valores (numéricos) en una sola columna <strong>de</strong> la tabla. La<br />
función AVG pue<strong>de</strong> ir precedida por la palabra clave DISTINCT lo cual promediará sólo<br />
los valores únicos. Si <strong>el</strong> resultado <strong>de</strong>l argumento es <strong>el</strong> conjunto vacío, AVG retorna NULL.<br />
Ejemplo :<br />
SELECT AVG (HORA_HASTA - HORA_DESDE)<br />
FROM VIAJE<br />
WHERE PATENTE_MOVIL = 'HL-8483';<br />
MIN (MAX): La función MIN (MAX) se usa <strong>para</strong> obtener <strong>el</strong> menor (mayor) valor en una<br />
columna. Ambas funciones operan sobre una colección <strong>de</strong> valores en una<br />
columna. Los valores no necesitan ser numéricos. Si <strong>el</strong> resultado <strong>de</strong>l argumento<br />
es <strong>el</strong> conjunto vacío, ambas retornan NULL.<br />
Ejemplo:<br />
SELECT MAX (HORA_HASTA - HORA_DESDE)
FROM VIAJE;<br />
SELECT MIN (HORA_HASTA - HORA_DESDE)<br />
FROM VIAJE;<br />
170<br />
COUNT(*): La función COUNT(*) se usa <strong>para</strong> contar la cardinalidad <strong>de</strong> una tabla sin<br />
<strong>el</strong>iminación <strong>de</strong> valores duplicados. En las funciones anteriores, cualquier valor<br />
nulo en <strong>el</strong> argumento se <strong>el</strong>imina antes que la función se aplique<br />
(indiferentemente <strong>de</strong> si se usa o no la cláusula DISTINCT) . COUNT(*) retorna<br />
cero si <strong>el</strong> resultado <strong>de</strong>l argumento es <strong>el</strong> conjunto vacío.<br />
Ejemplo:<br />
SELECT COUNT(*)<br />
FROM VIAJES<br />
WHERE PATENTE_MOVIL = 'HL-8483';<br />
A.2.1.2. Cláusula GROUP BY<br />
La cláusula GROUP BY en una sentencia SELECT reor<strong>de</strong>na lógicamente la<br />
tabla representada por la cláusula FROM en grupos, tal que <strong>de</strong>ntro <strong>de</strong> cada grupo<br />
todas las filas tienen <strong>el</strong> mismo valor <strong>para</strong> <strong>el</strong> campo dado en la cláusula GROUP<br />
BY (esto es conceptual; la tablas no se reor<strong>de</strong>na físicamente en la base <strong>de</strong> datos).<br />
Cada expresión en la cláusula SELECT <strong>de</strong>be ser reducible a valor simple <strong>de</strong>ntro<br />
<strong>de</strong> un grupo, es <strong>de</strong>cir, que pue<strong>de</strong> ser ya sea <strong>el</strong> mismo campo evaluado en la<br />
Cláusula GROUP BY (o talvez una expresión que lo contenga), un literal, o una<br />
función tal como SUM que opera sobre todos los valores <strong>de</strong> un grupo <strong>de</strong>ntro <strong>de</strong> un<br />
campo y que reduce todos aqu<strong>el</strong>los valores a un valor simple.
171<br />
GROUP BY no implica ORDER BY; <strong>para</strong> garantizar que <strong>el</strong> resultado<br />
aparezca en un <strong>de</strong>terminado or<strong>de</strong>n se <strong>de</strong>be especificar también la cláusula<br />
ORDER BY.<br />
Ejemplo:<br />
SELECT PATENTE_MOVIL, SUM(HORA_HASTA - HORA_DESDE)<br />
FROM VIAJE<br />
GROUP BY PATENTE_MOVIL;<br />
A.2.1.3. Cláusula HAVING<br />
La cláusula HAVING en una sentencia SELECT se usa <strong>para</strong> <strong>el</strong>iminar<br />
grupos, (tal como se usa WHERE <strong>para</strong> <strong>el</strong>iminar filas). Si se especifica, <strong>de</strong>be existir<br />
una cláusula GROUP BY también. La Expresión en la cláusula HAVING <strong>de</strong>be ser<br />
reducible a valor simple <strong>de</strong>ntro <strong>de</strong> un grupo.<br />
Ejemplo :<br />
SELECT PATENTE_MOVIL, SUM(HORA_HASTA - HORA_DESDE)<br />
FROM VIAJE<br />
GROUP BY PATENTE_MOVIL<br />
HAVING SUM(HORA_HASTA - HORA_DESDE) > 10;<br />
A.2.1.4. Cláusula ORDER BY<br />
Esta cláusula se utiliza en un comando SELECT <strong>para</strong> producir como<br />
resultado una r<strong>el</strong>ación en un or<strong>de</strong>n específico. En general, la r<strong>el</strong>ación resultado no
172<br />
se garantiza que esté en un or<strong>de</strong>n particular. De ahí que la cláusula ORDER BY<br />
se utilice <strong>para</strong> or<strong>de</strong>nar <strong>el</strong> resultado en alguna secuencia particular antes <strong>de</strong> que los<br />
datos sean <strong>de</strong>splegados.<br />
AL igual que la cláusula ORDER <strong>de</strong>l comando CREATE INDEX <strong>el</strong><br />
argumento pue<strong>de</strong> ser ya sea ASC o DESC. ASC es <strong>el</strong> valor por <strong>de</strong>fecto.<br />
También es posible i<strong>de</strong>ntificar columnas por su número <strong>de</strong> columna en lugar<br />
<strong>de</strong> su nombre, esto es, por la posición ordinal (<strong>de</strong> izquierda a <strong>de</strong>recha) <strong>de</strong> la<br />
columna en cuestión <strong>de</strong>ntro <strong>de</strong> la tabla resultado. Esta característica hace posible<br />
or<strong>de</strong>nar un resultado en base a una columna que no tiene nombre.<br />
Ejemplo:<br />
SELECT RUT, NOMBRE<br />
FROM CHOFER<br />
WHERE SYSDATE < FECHA_LCENCIA_HASTA<br />
ORDER BY 2 DESC;<br />
A.2.1.5. Cláusula EXIST<br />
La cláusula EXISTS en un comando SELECT representa <strong>el</strong> calificador <strong>de</strong><br />
existencia. La expresión se avaluara como verda<strong>de</strong>ra, si y sólo si, <strong>el</strong> resultado <strong>de</strong><br />
evaluar la sentencia “SELECT … FROM …” no es vacía, esto es, si y sólo si,<br />
existe un registro en la tabla dada en FROM <strong>de</strong>s<strong>de</strong> <strong>el</strong> niv<strong>el</strong> más externo <strong>de</strong> la<br />
consulta. La negación (NOT EXISTS) es especialmente importante <strong>para</strong> una cierta<br />
clase <strong>de</strong> <strong>consultas</strong> bastante más complejas que <strong>el</strong> común.<br />
Ejemplo :
SELECT PATENTE<br />
FROM MOVIL<br />
WHERE EXISTS (<br />
A.2.1.6. Sub<strong>consultas</strong>.<br />
SELECT *<br />
FROM VIAJE<br />
WHERE MOVIL.PATENTE =<br />
VIAJE.PATENTE_MOVIL);<br />
173<br />
Una Subconsulta en una cláusula SELECT es una expresión <strong>de</strong> la forma<br />
“SELECT - FROM - WHERE - GROUP BY - HAVING” que se anida <strong>de</strong>ntro <strong>de</strong> otra<br />
expresión. Las Sub<strong>consultas</strong> se usan comúnmente <strong>para</strong> representar un conjunto<br />
<strong>de</strong> valores que se buscan por medio <strong>de</strong> una condición “IN condición”. El sistema<br />
evalúa toda la consulta evaluando la Sub<strong>consultas</strong> anidadas.<br />
Ejemplos :<br />
* Retorna todos los móviles que tienen más <strong>de</strong> 10 horas <strong>de</strong> viaje.<br />
SELECT CHOFER.NOMBRE, MOVIL.PATENTE<br />
FROM MOVIL, CHOFER<br />
WHERE PATENTE IN (<br />
SELECT PATENTE_MOVIL<br />
FROM VIAJE<br />
WHERE (HORA_HASTA - HORA_DESDE) > 10)<br />
AND<br />
MOVIL.RUT_CHOFER = CHOFER.RUT;
A.2.2. Comando UPDATE<br />
174<br />
El comando DML UPDATE se usa <strong>para</strong> modificar valores <strong>de</strong> atributos <strong>de</strong><br />
una o más tuplas s<strong>el</strong>eccionadas. Al igual que con <strong>el</strong> comando SELECT la cláusula<br />
WHERE es la que s<strong>el</strong>ecciona la o las tuplas que serán modificadas <strong>de</strong>s<strong>de</strong> una<br />
r<strong>el</strong>ación simple. La cláusula adicional SET especifica los atributos que serán<br />
modificados y sus nuevos valores.<br />
La Sintaxis <strong>de</strong> UPDATE es la siguiente<br />
UPDATE nombre_<strong>de</strong>_tabla<br />
SET campo = expresion_escalar<br />
[, campo = expresion_escalar ] ...<br />
[ WHERE condicion ] ;<br />
Todos los registros en la tabla que satisfagan la condición serán<br />
modificados <strong>de</strong> acuerdo a sus asignaciones (“campo = expresion_escalar”) en la<br />
cláusula SET.<br />
El siguiente ejemplo <strong>de</strong>muestra <strong>el</strong> uso <strong>de</strong>l comando UPDATE en un<br />
Registro.<br />
UPDATE CHOFER<br />
SET DIRECCION = ‘Otra Dirección’,<br />
TELEFONO = 5555555<br />
WHERE RUT = 12657378<br />
El siguiente ejemplo <strong>de</strong>muestra <strong>el</strong> uso <strong>de</strong>l comando UPDATE <strong>para</strong> un<br />
conjunto <strong>de</strong> registros.
UPDATE CHOFER<br />
A.2.3. Comando DELETE<br />
SET VIGENCIA = ‘N’<br />
WHERE SYSDATE > FECHA_LICENCIA_HASTA;<br />
175<br />
El comando DML DELETE borra tuplas <strong>de</strong>s<strong>de</strong> una r<strong>el</strong>ación. Al igual que <strong>el</strong><br />
comando UPDATE pue<strong>de</strong> incluir la cláusula WHERE <strong>para</strong> s<strong>el</strong>eccionar las tuplas a<br />
ser <strong>el</strong>iminadas. Las tuplas son borradas sólo <strong>de</strong>s<strong>de</strong> una tabla a la vez.<br />
Dependiendo <strong>de</strong>l número <strong>de</strong> tuplas s<strong>el</strong>eccionadas por la condición en la cláusula<br />
WHERE será la cantidad (cero, una o más) <strong>de</strong> tuplas que serán <strong>el</strong>iminadas con un<br />
sólo comando DELETE. Si se omite la cláusula WHERE se asume que todas las<br />
tuplas <strong>de</strong> la r<strong>el</strong>ación <strong>de</strong>ben ser borradas, sin embargo la tabla permanece en la<br />
base <strong>de</strong> datos como una tabla vacía. (<strong>el</strong> comando DROP TABLE se usa <strong>para</strong><br />
<strong>el</strong>iminar completamente la tabla, aún si esta no está vacía).<br />
La sintaxis <strong>de</strong>l comando DELETE es la siguiente :<br />
DELETE<br />
FROM table<br />
[ WHERE condition ] ;<br />
El siguiente ejemplo borra una sola tupla en la tabla base:<br />
DELETE<br />
FROM MOVIL<br />
WHERE PATENTE = 'HL-8205' ;
El siguiente ejemplo borra todas las tuplas que satisfagan la condición<br />
DELETE<br />
A.2.4. Comando INSERT<br />
FROM MOVIL<br />
WHERE ANO
El siguiente es un ejemplo <strong>de</strong> la inserción <strong>de</strong> un sólo registro.<br />
INSERT<br />
INTO DUENO ( RUT, NOMBRE, VIGENCIA )<br />
VALUES ( 12657378, ‘MARIO CISTERNA’, ‘S’);<br />
El siguiente ejemplo muestra la inserción por medio <strong>de</strong> una Sub<strong>consultas</strong>.<br />
INSERT INTO CHOFER<br />
(RUT, NOMBRE, TELEFONO, DIRECCION, VIGENCIA)<br />
SELECT RUT, NOMBRE, TELEFONO, DIRECCION, VIGENCIA<br />
FROM DUENO WHERE VIGENCIA = ‘S’<br />
177
B. Indices B+<br />
178<br />
Los índices B + son índices multiniv<strong>el</strong>, que contienen n punteros P1, P2, … Pn<br />
y que pue<strong>de</strong>n contener hasta n-1 claves <strong>de</strong> búsqueda K1, K2, … Kn-1. Los valores<br />
<strong>de</strong> las claves <strong>de</strong> búsqueda se mantienen or<strong>de</strong>nados, así si i < j entonces Ki < Kj.<br />
Nodos Hoja: <strong>para</strong> i = 1, 2, … , n-1 <strong>el</strong> puntero Pi apunta a un registro <strong>de</strong> la tabla<br />
con clave Ki o a un cajón <strong>de</strong> punteros cada uno <strong>de</strong> los cuales apuntan a registros<br />
con clave Ki que se utiliza sólo si la clave <strong>de</strong> búsqueda no forma una clave<br />
primaria y <strong>el</strong> archivo no está or<strong>de</strong>nado según la clave <strong>de</strong> búsqueda. Está permitido<br />
que los nodos hojas guar<strong>de</strong>n a lo menos ⎡(n-1)/2⎤ valores, los rangos en cada hoja<br />
no se solapan, así si Li < Lj son nodos hojas y i < j entonces cada valor <strong>de</strong><br />
búsqueda <strong>de</strong> Li es menor que cada valor <strong>de</strong> Lj. El puntero Pn apunta al siguiente<br />
nodo hoja en <strong>el</strong> or<strong>de</strong>n <strong>de</strong> la clave <strong>de</strong> búsqueda, eso permite un mejor <strong>de</strong>sempeño<br />
en búsquedas secuenciales.<br />
Nodos Internos: Los nodos internos tienen la misma estructura que los nodos<br />
hoja, excepto que todos los punteros son punteros a nodos <strong>de</strong>l árbol. Cada nodo<br />
pue<strong>de</strong> guardar hasta n punteros y <strong>de</strong>be guardar a lo menos ⎡n/2⎤ punteros. El<br />
número <strong>de</strong> punteros <strong>de</strong> un nodo se llama grado <strong>de</strong> salida <strong>de</strong>l nodo.<br />
Si un nodo tiene m punteros, <strong>para</strong> i = 2, … m-1, <strong>el</strong> puntero Pi apunta al<br />
subárbol que contiene los valores <strong>de</strong> clave <strong>de</strong> búsqueda menores que Ki y<br />
mayores que Ki-1. Pm apunta a la parte <strong>de</strong>l subarbol que contiene los valores <strong>de</strong> la<br />
clave que son mayores o iguales a Km-1 y a su vez P1 apunta a la parte <strong>de</strong>l<br />
subarbol que contiene los valores <strong>de</strong> clave menores o iguales a K1. El requisito <strong>de</strong>
que todos los nodos tengan ⎡n/2⎤ punteros se impone a todos los nodos internos<br />
menos a la raíz.<br />
179<br />
Otro requisito <strong>de</strong> los árboles B + es que estén equilibrados. Es <strong>de</strong>cir, la<br />
longitud <strong>de</strong> cada camino <strong>de</strong>s<strong>de</strong> la raíz hasta un nodo hoja es la misma.<br />
Para procesar una consulta sobre <strong>el</strong> árbol se tiene que recorrer un camino<br />
en <strong>el</strong> árbol <strong>de</strong>s<strong>de</strong> la raíz hasta algún nodo hoja. Si hay K valores <strong>de</strong> la clave <strong>de</strong><br />
búsqueda en e archivo, este camino no será más largo que ⎡log[n/2](K)⎤ En la<br />
práctica sólo se acce<strong>de</strong> a algunos nodos, Generalmente un nodo se construye<br />
<strong>para</strong> tener <strong>el</strong> mismo tamaño que un bloque <strong>de</strong> disco, <strong>el</strong> cual ocupa normalmente<br />
4Kb. Con una clave <strong>de</strong> búsqueda <strong>de</strong>l tamaño <strong>de</strong> 12 bytes y un tamaño <strong>de</strong> puntero<br />
a disco <strong>de</strong> 8 bytes, n está alre<strong>de</strong>dor <strong>de</strong> 200. Incluso con una estimación más<br />
conservadora <strong>de</strong> 32 bytes <strong>para</strong> <strong>el</strong> tamaño <strong>de</strong> la clave <strong>de</strong> búsqueda, n está próximo<br />
a 100.<br />
Con n = 100, si se tiene 1.000.000 <strong>de</strong> la clave <strong>de</strong> búsqueda en la tabla, una<br />
búsqueda necesita solamente ⎡log50(1.000.000)⎤ = 4 accesos a nodos. Por lo tanto<br />
se necesita leer a lo sumo cuatro bloques <strong>de</strong>l disco <strong>para</strong> realizar la búsqueda.<br />
Índices asociativos.<br />
En una organización <strong>de</strong> archivos por asociación se obtiene la dirección <strong>de</strong>l<br />
bloque <strong>de</strong> disco mediante <strong>el</strong> cálculo <strong>de</strong> una función <strong>de</strong> asociación sobre <strong>el</strong> valor <strong>de</strong><br />
la clave <strong>de</strong>l registro. Se utiliza <strong>el</strong> término cajón (bucket) <strong>para</strong> indicar una unidad <strong>de</strong><br />
almacenamiento que pue<strong>de</strong> guardar uno o más registros. Formalmente, sea K <strong>el</strong><br />
conjunto <strong>de</strong> todos los valores <strong>de</strong> claves <strong>de</strong> búsqueda y sea B <strong>el</strong> conjunto <strong>de</strong> todas<br />
las direcciones <strong>de</strong> cajón, una función <strong>de</strong> asociación h es una función <strong>de</strong> K a B.<br />
Para realizar una búsqueda con valor Ki en la clave <strong>de</strong> búsqueda simplemente se<br />
calcula h(Ki), y luego se busca en <strong>el</strong> cajón al que apunta esa dirección, como<br />
existe la posibilidad <strong>de</strong> que dos claves <strong>de</strong> búsqueda tengan <strong>el</strong> mismo valor <strong>de</strong>
180<br />
asociación, se <strong>de</strong>be buscar luego en <strong>el</strong> cajón las tuplas que coincidan con los<br />
valores <strong>de</strong> búsqueda <strong>de</strong> la clave.<br />
La peor función <strong>de</strong> asociación posible asigna todos los valores <strong>de</strong> la clave<br />
<strong>de</strong> búsqueda al mismo cajón, una función i<strong>de</strong>al es aqu<strong>el</strong>la que distribuye las<br />
claves almacenadas uniformemente a traves <strong>de</strong> los cajones <strong>de</strong> manera que cada<br />
uno <strong>de</strong> estos tenga <strong>el</strong> mismo número <strong>de</strong> registros.<br />
Un índice asociativo (hash in<strong>de</strong>x) organiza las claves <strong>de</strong> búsqueda con sus<br />
punteros asociados <strong>de</strong>ntro <strong>de</strong> una estructura <strong>de</strong> archivo asociativo. Se usa <strong>el</strong><br />
termino índice asociativo <strong>para</strong> <strong>de</strong>notar las estructuras <strong>de</strong> archivo asociativo, asi<br />
como los índices secundarios asociativos. En rigor, los índices asociativos son<br />
sólo estructuras <strong>de</strong> índices secundarios.<br />
Para más referencias se recomienda consultar [Silberschatz97] capítulo 11<br />
(In<strong>de</strong>xación y Asociación) y [Comer79].
C. Métodos <strong>de</strong> almacenamiento <strong>de</strong> Datos.<br />
181<br />
En la mayor parte <strong>de</strong> los sistemas informáticos hay varios tipos <strong>de</strong><br />
almacenamiento <strong>de</strong> datos. Estos medios <strong>de</strong> almacenamiento se pue<strong>de</strong>n clasificar<br />
por la v<strong>el</strong>ocidad con que se pue<strong>de</strong> tener acceso a los datos, por <strong>el</strong> costo <strong>de</strong><br />
adquisición <strong>de</strong>l medio y por la fiabilidad <strong>de</strong>l medio.<br />
La clasificación más general y la que se presentará a continuación es una mezcla<br />
entre las medidas <strong>de</strong> v<strong>el</strong>ocidad y la fiabilidad <strong>de</strong>l medio.<br />
Almacenamiento Primario.<br />
• Caché: La forma <strong>de</strong> almacenamiento más rápida y más costosa, se<br />
gestiona por hardware.<br />
• Memoria Principal : Es <strong>el</strong> medio don<strong>de</strong> operan las instrucciones <strong>de</strong><br />
maquina y los datos disponibles <strong>para</strong> los programas, este tipo <strong>de</strong><br />
almacenamiento es voluble a fallos.<br />
• Memoria Flash: (Ellectrically Erasable Programmable Read Only Memory)<br />
EEPROM, medio <strong>de</strong> almacenamiento que pue<strong>de</strong> aguantar los fallos<br />
<strong>el</strong>éctricos. La lectura toma menos <strong>de</strong> 100 nanosegundos, pero la escritura<br />
tarda <strong>de</strong> 4 a 10 microsegundos. Se borra por bancos <strong>de</strong> memoria. Este tipo<br />
<strong>de</strong> memoria se ha hecho popular como sustituta <strong>de</strong> discos magnéticos <strong>para</strong><br />
guardar pequeños volúmenes <strong>de</strong> datos.<br />
Almacenamiento secundario (en conexión)
182<br />
• Discos magnéticos: Principal medio <strong>de</strong> almacenamiento a largo plazo que<br />
resiste los fallos <strong>de</strong> energía. Generalmente se guarda toda la base <strong>de</strong> datos<br />
en discos magnéticos, pero <strong>para</strong> tener acceso a los datos hay que<br />
trasladarlos hacia la memoria principal. El almacenamiento en disco se<br />
llama tambien almacenamiento <strong>de</strong> acceso directo dado que los discos<br />
pue<strong>de</strong>n leer en cualquier or<strong>de</strong>n a diferencia <strong>de</strong> los medios <strong>de</strong><br />
almacenamiento secuencial.<br />
Almacenamiento terciario (sin conexión)<br />
• Almacenamiento óptico: CDROM (Compact Disc Read Only Memory) y<br />
WORM (Write Once Read Only memory), permiten la grabación una sola<br />
vez pero no <strong>el</strong> borrado o sobre-escritura.<br />
• Almacenamiento en Cinta: Almacenamiento secuencial comúnmente<br />
utilizado <strong>para</strong> respaldos <strong>de</strong> la información puesto que es más lento tanto en<br />
lecturas como escrituras.<br />
C.1. Discos Magnéticos.<br />
Los discos magnéticos proporcionan la parte principal <strong>de</strong>l almacenamiento<br />
secundario <strong>de</strong> los SGBD. La capacidad <strong>de</strong> almacenamiento <strong>de</strong> un sólo disco varía<br />
actualmente <strong>de</strong>s<strong>de</strong> los 10 Mb hasta los 100 Gb. Una Base <strong>de</strong> datos comercial<br />
gran<strong>de</strong> típicamente pue<strong>de</strong> necesitar <strong>de</strong>cenas o centenas <strong>de</strong> discos.<br />
Físicamente, un disco esta compuesto por platos, cada plato es <strong>de</strong> metal o vidrio<br />
cubierto por un material magnético, giran a 60, 90 o 120 Revoluciones por<br />
segundo. La superficie se divi<strong>de</strong> lógicamente en pistas y las pistas en sectores.
183<br />
Cada cara <strong>de</strong>l plato tiene una cabeza <strong>de</strong> lectura escritura, cada una <strong>de</strong> estas<br />
cabezas están montadas en un dispositivo llamado brazo <strong>de</strong>l plato. Al conjunto <strong>de</strong><br />
pistas i-ésimas <strong>de</strong> cada plato se le <strong>de</strong>nomina cilindro.<br />
Una unidad controladora <strong>de</strong> disco es una interfaz entre <strong>el</strong> sistema informático y <strong>el</strong><br />
hardware. Esta unidad acepta or<strong>de</strong>nes <strong>de</strong> alto niv<strong>el</strong> <strong>para</strong> leer o escribir en un<br />
sector e inicia las acciones tales como <strong>de</strong>splazar <strong>el</strong> brazo <strong>de</strong> disco a la pista<br />
a<strong>de</strong>cuada o leer y/o escribir los datos. Un controlador <strong>de</strong> disco posee a<strong>de</strong>más una<br />
unidad <strong>de</strong> comprobación <strong>de</strong> suma (checksum) <strong>para</strong> cada sector que se escribe,<br />
cuando se vu<strong>el</strong>ve a leer un sector <strong>de</strong> disco se vu<strong>el</strong>ve a calcular la suma a partir <strong>de</strong><br />
los datos recuperados y se com<strong>para</strong> con la suma <strong>de</strong> comprobación guardada; si<br />
los datos se han <strong>de</strong>teriorado, resulta muy probable que las sumas no coincidan, si<br />
este es <strong>el</strong> caso, <strong>el</strong> controlador volverá a intentar varias veces la lectura; si <strong>el</strong> error<br />
persiste <strong>el</strong> controlador informará al sistema <strong>de</strong> un fallo <strong>de</strong> lectura.<br />
Un disco se conecta a un sistema informático o a un controlador por medio <strong>de</strong> una<br />
conexión <strong>de</strong> alta v<strong>el</strong>ocidad, su<strong>el</strong>e utilizarse la Interfaz <strong>de</strong> conexión <strong>para</strong> sistemas<br />
informáticos pequeños (Small Computer-System Interconnect Interface, “escasi”)<br />
sin embargo los sistemas <strong>de</strong> alto rendimiento su<strong>el</strong>en disponer <strong>de</strong> un bus más<br />
rápido <strong>para</strong> conectarse a los discos (fibra u otro medio combinado).<br />
C.1.1. Medidas <strong>de</strong> rendimiento <strong>para</strong> los discos.<br />
Las principales medidas <strong>de</strong> la calidad <strong>de</strong> un disco son la capacidad, <strong>el</strong> tiempo <strong>de</strong><br />
acceso, la v<strong>el</strong>ocidad <strong>de</strong> transferencia y la fiabilidad.<br />
• Tiempo <strong>de</strong> búsqueda. Tiempo que le toma al disco <strong>de</strong>splazar <strong>el</strong> brazo <strong>para</strong><br />
que se ubique sobre la pista correcta.
184<br />
• Tiempo medio <strong>de</strong> búsqueda. Media estadística <strong>de</strong> los tiempos <strong>de</strong><br />
búsqueda medido en una sucesión <strong>de</strong> búsquedas aleatorias uniformemente<br />
distribuidas y que es aproximadamente 1/3 <strong>de</strong>l peor <strong>de</strong> los tiempos (2 a 30<br />
milisegundos)<br />
• Tiempo <strong>de</strong> latencia rotacional. Tiempo transcurrido hasta que aparece <strong>el</strong><br />
sector que se <strong>de</strong>sea bajo la cabeza <strong>de</strong> lectura/escritura.<br />
• Tiempo <strong>de</strong> Acceso. Tiempo medio <strong>de</strong> búsqueda + tiempo <strong>de</strong> latencia<br />
rotacional.<br />
• V<strong>el</strong>ocidad <strong>de</strong> transferencia <strong>de</strong> datos. V<strong>el</strong>ocidad a la que se pue<strong>de</strong>n<br />
recuperar o guardar datos luego <strong>de</strong>l tiempo <strong>de</strong> acceso.<br />
• Tiempo medio entre fallos. Cantidad <strong>de</strong> tiempo que se pue<strong>de</strong> esperar que<br />
<strong>el</strong> sistema funcione <strong>de</strong> manera continua sin tener que fallar (entre 30.000 a<br />
800.000 horas)