¿Qué es un lenguaje de consulta a base de datos? ¿Qué es una consulta de actualización en base de datos? ¿Cuál es el lenguaje que crea, modifica y borra datos? ¿Qué es el lenguaje de SQL?
Lenguajes de consulta y actualización de datos
Álgebra relacional
El álgebra relacional es un lenguaje de consulta procedimental (no declarativo) que sirve de base formal para el lenguaje SQL-DML de manipulación de datos (que sí es declarativo). Consiste en un conjunto de operaciones que describen paso a paso (de ahí que sea procedimental) cómo computar una respuesta sobre las relaciones definidas en el modelo relacional. Se utiliza como una representación intermedia de una consulta a una base de datos, permitiendo obtener una versión más optimizada y eficiente de la misma.
La unidad de trabajo del álgebra relacional son las relaciones (tablas), sobre las que se aplican una serie de operaciones definidas, que pueden ser de dos categorías distintas:
El resultado de una operación siempre es una nueva relación, lo que permite componer diferentes operaciones del álgebra relacional formando expresiones del álgebra relacional.
Operaciones unarias
Selección (σ)
La selección permite seleccionar un subconjunto de tuplas (filas) de una relación (R), trayendo como resultado todas aquellas que cumplan las condiciones:
σ_P (R)
Se pueden realizar comparaciones en la condición, e incluso conectar distintas condiciones usando operadores lógicos.
Si ninguna tupla cumple las condiciones (operación contradictoria), el resultado es vacío. Por el contrario, si todas las tuplas cumplen las condiciones, el resultado será la misma relación.
Proyección ()
La proyección permite extraer atributos (A_1,A_2,…,A_n ) de una relación, dando como resultado un subconjunto vertical de atributos de la relación (R):
_(A_1,A_2,…,A_n ) (R)
Utilizando la proyección se pueden reordenar los atributos y crear nuevas columnas en la relación. Incluso, se pueden establecer los valores que tendrán las tuplas del nuevo atributo.
Renombramiento (ρ)
El renombramiento permite poner nombre a las expresiones del álgebra relacional:
ρ_A (R)
Esta operación es útil en las consultas SQL para acortar los nombres de las tablas y escribir el código más sintético.
Las relaciones R por sí mismas se consideran expresiones (triviales) del álgebra relacional. Por tanto, también se puede aplicar la operación renombramiento a una relación R para obtener la misma relación con un nombre nuevo. Hacer esto es obligatorio cuando se usa dos veces la misma relación en una operación (por ejemplo, cuando las relaciones son recursivas).
Operaciones binarias
Unión (∪)
La unión retorna el conjunto de tuplas que están en la relación R, en la relación S, o en ambas. R y S deben ser relaciones compatibles.
R∪S
Las tuplas que están en las dos relaciones aparecerán una sola vez en el resultado.
Para que las relaciones sean compatibles deben tener la misma cantidad de atributos y los dominios ser compatibles (no podrían tener distintos tipos de datos).
Diferencia (-)
La diferencia entrega todas aquellas tuplas que están en R pero no en S. R y S deben ser relaciones compatibles:
R-S
Intersección (∩)
La intersección, como en teoría de conjuntos, corresponde al conjunto de todas las tuplas que están en R y en S, siendo R y S relaciones compatibles.
R∩S
Producto cartesiano (×)
El producto cartesiano entrega una relación, cuyo esquema corresponde a una combinación de todas las tuplas de R con cada una de las tuplas de S, y sus atributos corresponden a los de R seguidos por los de S:
R×S
Esta operación trae dificultades, ya que multiplica cada registro de R por cada uno de los de S sin importar si en la realidad existe o no la relación. Por ello existen otras operaciones que la mejoran.
Reunión natural (⋈)
La reunión natural hace un producto cartesiano (×) de sus dos argumentos y realiza una selección (σ) forzando la igualdad de atributos que aparecen en ambas relaciones, eliminando repetidos:
R⋈S
Se trata de un producto cartesiano con una condición de unión embebida.
Reunión externa
La reunión externa es una variante de la reunión natural en la que se intenta mantener toda la información de los operandos, incluso para aquellas filas que no participan en la reunión. Se rellenan con null las tuplas que no tienen correspondencia en la reunión. Posee 3 variantes:
- Izquierda: se tienen en cuenta todas las filas del primer operando.
- Derecha: se tienen en cuenta todas las filas del segundo operando.
- Completa: se tienen en cuenta todas las filas de ambos operandos.
Procesamiento y optimización de consultas
El procesamiento de consultas hace referencia a una serie de actividades implicadas en la extracción de datos de una base de datos. Estas actividades incluyen la traducción de consultas expresadas en lenguajes de bases de datos de alto nivel en expresiones implementadas en el nivel físico del sistema, así como transformaciones de optimización de consultas y la evaluación real de las mismas.
- Análisis y traducción
Antes de empezar el procesamiento de una consulta, el sistema debe traducirla a una forma utilizable. La representación interna que utiliza de la consulta es el álgebra relacional extendido. Durante la generación del formato interno de una consulta, el analizador comprueba la sintaxis de la consulta del usuario y verifica que los nombres de las relaciones que aparecen en ella sean nombres de relaciones en la base de datos.
Posteriormente, se construye un árbol para el análisis de la consulta, que se transformará en una expresión del álgebra relacional. La estructura es la de árbol invertido: empieza a partir de una raíz que indica el resultado que se busca y se subdivide en las distintas operaciones que debe resolver previamente para llegar al mismo. Las operaciones del último nivel son las que se realizan primero.
Si la consulta estuviera expresada en términos de una vista, la fase de traducción también sustituye todas las referencias a vistas por las expresiones del álgebra relacional que las definen.
El objetivo del optimizador es determinar distintos planes de ejecución de una consulta y determinar cuál es el óptimo. Dada una consulta, generalmente hay varios métodos para obtener la respuesta y cada una de ellas se puede expresar de diferentes maneras y traducirse a distintas expresiones del álgebra relacional. Además, se puede ejecutar cada operación del álgebra relacional utilizando alguno de los diferentes algoritmos. La optimización de consultas es el proceso de selección del plan de ejecución de las consultas más eficiente de entre las muchas estrategias generalmente disponibles para el procesamiento de una consulta dada, especialmente si la misma es compleja. No se espera que los usuarios escriban las consultas de modo que puedan procesarse de manera eficiente.
Para determinar el plan óptimo, los SGBD utilizan una conjunción de dos criterios:
Optimización basada en el costo
Optimización basada en heurísticas
Se espera que el sistema cree un plan de ejecución que minimice el costo de la ejecución de las consultas, el cual normalmente viene dado por:
- Operaciones de E/S en el disco.
- CPU (procesamiento).
- Conectividad.
Estos costos los estima gracias a los datos que toma del catálogo de estadísticas.
La optimización basada en costos muchas veces genera un conjunto grande de planes y determinar el óptimo entre ellos puede requerir un gran esfuerzo de cómputo. Por ello, los SGBD también usan heurísticas, es decir, una serie de reglas predefinidas que indican cómo optimizar los planes. Sin embargo, a veces también se vuelven ineficientes porque no toman en cuenta las circunstancias en las cuales se procesa la consulta (capacidad de hardware disponible, etc.).
Para armar los planes de ejecución y elegir el mejor, el optimizador utiliza:
- Expresiones equivalentes: son expresiones del álgebra relacional que producen el mismo resultado.
- Primitivas de evaluación: algoritmos para realizar las operaciones indicadas en las expresiones del álgebra relacional.
- Evaluación: determina si cada plan se puede ejecutar utilizando materialización o encauzamiento para determinar el plan óptimo.
Expresiones equivalentes
Se dice que dos expresiones del álgebra relacional son equivalentes si, en cada ejemplar legal de la base de datos, las dos expresiones generan el mismo conjunto de tuplas (un ejemplar legal de la base de datos es la que satisface todas las restricciones de integridad especificadas en el esquema de la base de datos). El orden de las tuplas resulta irrelevante; puede que las dos expresiones generen las tuplas en órdenes diferentes, pero se considerarán equivalentes siempre que el conjunto de tuplas sea el mismo.
Estadísticas
Para estimar cuál es el costo de cada expresión del álgebra relacional, el optimizador utiliza estadísticas que le permiten arribar al resultado. Para obtenerlas utilizan datos de tablas, índices y atributos. Los catálogos de los SGBD almacenan la siguiente información estadística sobre las relaciones de las bases de datos:
- El número de tuplas de la relación r.
- El número de bloques que contienen tuplas de la relación r.
- El tamaño de cada tupla de la relación r en bytes.
- El factor de bloqueo de la relación r (es decir, el número de tuplas de la relación r que caben en un bloque).
- El número de valores distintos que aparecen en la relación r para un atributo A. Este valor es igual a A(r), pero si A es una clave de la relación r el valor es igual al número de tuplas de la relación.
- Las estadísticas sobre los índices, como las alturas de los árboles B + y el número de páginas hojas de los índices. Al momento de realizar un análisis de optimización, se toma en cuenta la existencia de índices que estén agrupados en función del atributo que se está usando en la consulta; de lo contrario, no aportan a una mejora en la optimización de la ejecución de la consulta.
A partir de los mismos, el SGBD construye histogramas para almacenar la distribución de valores de cada atributo, la cual es una forma muy común de almacenar estadísticas.
En los histogramas, los valores del atributo se dividen en una serie de rangos, y con cada rango el histograma asocia el número de tuplas cuyo valor del atributo se halla en ese rango. Registran el número de los valores distintos en cada rango, además del número de tuplas con en ese rango.
Es importante tener en cuenta que las estimaciones no son muy precisas, ya que se basan en suposiciones que pueden no cumplirse exactamente. El plan de evaluación de consultas que tenga el costo estimado de ejecución más reducido puede, por tanto, no tener el costo real de ejecución más bajo.
Un motivo por el cual las estimaciones no son precisas es porque deben actualizarse cada vez que se modifica una relación de la base de datos, lo cual supone una sobrecarga sustancial de los recursos del sistema. Por lo tanto, lo que se suele hacer es actualizar las estadísticas en los momentos de menor carga de trabajo.
Primitivas de evaluación
Una vez que se decide cuál es la mejor expresión del álgebra relacional para ejecutar una consulta, hay que determinar cuál es la mejor manera de llevarla a cabo. No basta con proporcionar la expresión, sino que hay que anotar en ella las instrucciones que especifiquen cómo evaluar cada operación. Las primitivas de evaluación son operaciones del álgebra relacional anotadas con instrucciones sobre su evaluación. La secuencia de operaciones primitivas que se pueden utilizar en la evaluación de una consulta establece un plan de ejecución de la consulta.
Operación selección
Si la operación que se va a llevar a cabo es una selección, los algoritmos que permiten implementar son:
- Búsqueda lineal: se explora cada uno de los bloques del archivo y se comprueban todos los registros para determinar si satisfacen o no la condición de selección.
- Búsqueda binaria: requiere que el archivo esté ordenado según un atributo y que la condición de la selección sea una comparación de igualdad en ese atributo. Divide la tabla en mitades, descartando aquellas que no poseen el valor buscado.
- Índice primario: selecciona sobre un índice árbol B+ agrupado.
- Índice secundario: selecciona sobre un índice árbol B + no agrupado.
- Bucle analizado: se establece una operación en bucle en la cual para cada fila de la tabla externa se examina si el valor del atributo establecido para realizar la reunión coincide con el valor del mismo atributo de la tabla interna. Se examina cada pareja de tuplas en las dos relaciones. Este procedimiento puede hacerse así o en alguna de sus dos variantes:
- Bucle anidado por bloques: se empareja cada bloque de la relación interna con cada bloque de la relación externa. En cada par de bloques se empareja cada tupla de un bloque con cada tupla del otro bloque para generar todos los pares de tuplas. Al igual que antes se añaden al resultado todas las parejas de tuplas que satisfacen la condición de la reunión.
- Bucle analizado indexado: si se dispone de un índice sobre el atributo de la reunión del bucle interno, se pueden sustituir las exploraciones de archivo por búsquedas en el índice. Para cada cúpula de la relación externa se utiliza el índice para buscar en tuplas de la relación interna que cumplan con la condición de reunión.
- Reunión por mezcla: asocia un puntero con cada relación. Al comienzo, estos punteros apuntan a la primera dupla de sus respectivas relaciones. Según avanza el algoritmo, el puntero se mueve a través de la relación. De este modo se leen en la tabla interna un grupo de tuplas de una relación con el mismo valor en los atributos de la reunión. Después, las tuplas correspondientes de la otra relación (si las hay) se leen y se procesan según se están leyendo.
- Reunión por asociación: se utiliza una función de asociación h para dividir las tuplas de ambas relaciones. La idea es dividir las tuplas de cada relación en conjuntos con el mismo valor de la función de asociación en los atributos de la reunión.
- Materialización: se evalúa una operación por vez, en el orden apropiado, y por cada una se crea una relación (tabla) temporal para su inmediata utilización. Los resultados de cada operación intermedia se crean (materializan) para utilizarse a continuación en la evaluación de las operaciones del siguiente nivel. Si la relación temporal excede la capacidad de memoria principal, debe ser escrita en disco para recuperarla, lo que implica más cantidad de operaciones de E/S.
- Encauzamiento: comienza la operación siguiente sin haber finalizado la operación actual. Se evalúan varias operaciones de manera simultánea en un cauce, con los resultados de una operación pasados a la siguiente, sin la necesidad de almacenar relaciones temporales. La combinación de operaciones en un encauzamiento elimina el costo de leer y escribir relaciones temporales, aprovechando mejor los recursos del sistema. Sin embargo, no siempre es posible realizarla: depende de la naturaleza de la operación (hay veces en las que se requiere que se finalice una por completo antes de empezar la siguiente).
- Cuando el plan de ejecución óptimo ya está definido y se encuentra en memoria, el SGBD puede saltarse todos los pasos de procesamiento si la siguiente consulta es significativamente similar.
- Las vistas también ayudan a optimizar ya que, junto con ella, se guarda el plan de ejecución de la misma. No siempre optimizan: si cambia un índice o se modifican significativamente la cantidad de registros o atributos puede ser que ese plan ya no sea el óptimo.
- Procesador: revisar qué tan exigido se encuentra.
- Memoria principal:
- Tipo (MHz que posee o tecnología, DDR3 o DDR4).
- Cantidad.
- Asignaciones: qué procesos consumen memoria junto con el SGBD (asignándole más cantidad a éste).
- Accesos a disco: Un factor importante en el ajuste de un sistema de procesamiento de transacciones, es asegurarse de que el subsistema de disco puede admitir la velocidad en que se solicitan las operaciones de E/S. El factor limitador no es la capacidad del disco, sino la velocidad a la que se puede tener acceso a los datos aleatorios. El número de operaciones de E/S por transacción puede reducirse almacenando más datos en la memoria principal. Los aspectos que se pueden revisar son:
- Tipos de disco: tecnología.
- Configuración: en sistema operativo.
- Arquitecturas: evaluar qué esquemas RAID son más eficientes según la frecuencia con la que se actualicen los datos.
- Asignaciones: archivos log, temporales, datos, etc.
- Tamaño de memoria intermedia: asignaciones de caché para datos, para procedimientos almacenados, etc.
- Tamaño de bloques y de extensiones: aumentar tamaño para ser más eficiente y traer más registros en menos operaciones de E/S.
- Asignación a discos de los archivos.
- Actualización de estadísticas.
- Reorganización de archivos de páginas de datos: cuando hay varias actualizaciones y eliminaciones, los bloques quedan menos aprovechados (algunos con más datos que otros); por eso reorganizar archivos en los bloques permite que queden guardados en forma consecutiva.
- Regeneración de índices: cuando se modificó varias veces un índice se lo puede volver a crear con todos los valores insertados con posterioridad a su creación original.
- Creación, modificación o eliminación de índices:
- La creación de un índice puede optimizar varias consultas. Crear un índice secundario sobre un atributo A permite ejecutar más rápido consultas donde:
- Se seleccione un valor del atributo A (o rango de valores).
- Reunión natural con el atributo A.
- Obtener todos los valores de atributos para un valor de atributo A.
- Sin embargo, también puede ralentizar otras operaciones:
- Insertar un nuevo valor para el atributo A (en un nuevo registro), ya que con cada inserción se debe actualizar el índice (pasa lo mismo con la actualización de un registro).
- Eliminar un valor para el atributo A (en un registro) ya que también se deberá actualizar el índice.
- Por eso, a veces eliminar índices optimiza el rendimiento. Sin embargo, hay otras operaciones que no se ven afectadas con la creación del índice:
- Modificación de datos que no sean parte del índice secundario.
- Insertar registros en otra entidad, siempre que no implique la inserción de un registro en la tabla con el atributo A.
- Repensar el modelo de datos para que tenga una mayor claridad semántica.
- Diseño lógico:
- Dividir tablas mediante relaciones 1 a 1: es posible dividir tablas extensas con varios atributos en varias tablas que agrupan los atributos más usados bajo algún criterio. Se genera redundancia, pero permite que entren más datos en un bloque, teniendo que leer menos bloques en una consulta.
- Elección de tipos de datos adecuados para cada atributo: la cantidad de memoria que ocupa un tipo de dato hace que varíe el tamaño de los registros y, por ende, el factor de bloqueo.
- Datos desnormalizados (redundantes): si bien implican que hay que realizar más esfuerzo para asegurarse de que la relación es consistente siempre que se realice una actualización, las relaciones desnormalizadas a veces mejoran el rendimiento. Esto ocurre sobre todo en consultas que se realizan con frecuencia y que requieren llevarse a cabo con la máxima eficiencia posible. Agregar una restricción de clave foránea en una tabla ralentiza operaciones de inserción, actualización o eliminación, ya que antes de realizarlas el SGBD debe verificar la integridad referencial.
- Diseño lógico/físico:
- Uso de vistas materializadas de datos calculados: una vista materializada es una vista cuyo contenido se calcula y se almacena. Constituyen datos redundantes, en el sentido de que su contenido puede deducirse de la definición de la vista y del resto del contenido de la base de datos. No obstante, resulta mucho más económico en muchos casos leer el contenido de una vista materializada que calcular el contenido de la vista ejecutando la consulta que la define. Deben usarse con cuidado, no obstante, dado que no sólo supone una sobrecarga de espacio almacenarlas, sino que, lo que es más importante, su mantenimiento también supone una sobrecarga de tiempo.
- Manejo de particiones.
- Costo de actualización de los índices versus mejora en consultas:
- Índices agrupados e índices secundarios.
- Elección de atributos a indizar.
- Orden de los atributos en los índices compuestos: son aquellos que poseen más de una clave de búsqueda. Es importante el orden de los atributos porque primero se busca por el primer atributo y luego por el siguiente, pero no viceversa.
- Elección de RAID: un RAID 5 requiere cálculo de paridad, lo que ralentiza operaciones de inserción, actualización o eliminación.
- Escritura de las consultas:
- Traer la menor cantidad de datos posibles (evitar el *, traer sólo los datos que se usan, etc.).
- Tratar de evitar las iteraciones: en consultas anidadas complejas es mejor reemplazarlas por una reunión natural.
- Que el optimizador use al máximo su potencial:
- Uso de cursores limitado: un cursor recorre la tabla registro a registro realizando operaciones en cada uno (en todos o en aquellos que cumplan cierta condición).
- Trabajo con abstracción de datos desde la aplicación.
- Usar hints en casos muy específicos (orden de la reunión, uso de índices, etc.): un hint hace que el SGBD no utilice su optimizador de la forma predeterminada sino de una forma específica indicada por el usuario. Por eso, su uso debería ser limitado y es poco recomendable.
- Manejo especial de niveles de aislamiento en las transacciones.
- Evaluar si los motivos por los cuales una consulta tarda más de lo que esperan los usuarios es por conflictos con otras consultas simultáneas. Al no considerar el plan de ejecución, puede ver qué tareas estaba haciendo el SGBD al momento de ejecutar la consulta en cuestión.
- Puede detectar tareas que tardan mucho, pudiendo aplicar estrategias:
- Proactivas: para asegurar la performance de operaciones críticas. Puede sugerir la creación de índices, reorganizaciones, etc.
- Reactivas: cuando hay problemas con el tiempo de respuesta.
Operación reunión
Si la operación que se va a llevar a cabo es una reunión, los algoritmos que permiten implementar son:
Evaluación
Una vez definidas las expresiones de álgebra relacional que se llevarán a cabo y qué algoritmo usar para su ejecución, se debe evaluar la expresión total que contiene varias operaciones. En este punto es necesario definir cómo se realizará esa evaluación:
Otras formas de optimizar el procesamiento de consultas
Ajuste de rendimiento
Se puede hacer que las aplicaciones se ejecuten significativamente más rápido mediante el ajuste del rendimiento, que consiste en hallar y eliminar los cuellos de botella y en añadir el hardware adecuado. El ajuste del rendimiento de un sistema implica ajustar varios parámetros y opciones de diseño para mejorar su rendimiento en una aplicación concreta.
El rendimiento de la mayor parte de los sistemas (al menos, antes de ajustarlos) suele quedar limitado principalmente por el que presenta un componente o unos pocos, denominados cuellos de botella. Al ajustar un sistema, primero hay que intentar descubrir los cuellos de botella y luego eliminarlos, mejorando el rendimiento de los componentes que los generan. Cuando se elimina un cuello de botella puede ocurrir que otro componente se transforme en cuello de botella. La mejora del rendimiento de un componente que no sea un cuello de botella hace poco para mejorar la velocidad global del sistema.
Los DBA pueden ajustar los sistemas de bases de datos en tres niveles: hardware (nivel más inferior), parámetros del SGBD y el diseño del esquema y las transacciones (nivel más superior). Los tres niveles de ajuste interactúan entre sí; hay que considerarlos en conjunto al ajustar los sistemas.
Ajustes del hardware
Una vez que ya están optimizados todos los otros niveles ajustables, queda revisar el hardware. Los ajustes en el mismo pueden mejorar sustancialmente el procesamiento de consultas.
Los aspectos de hardware a revisar son:
Ajustes del DBA con el SGBD
Diseño del esquema
El diseño del esquema puede mejorar la performance de las consultas:
Desarrollo de transacciones
Se entiende como transacción a una unidad de consulta. Las consultas complejas que contienen subconsultas anidadas no suelen ser muy bien optimizadas por los optimizadores actuales de bases de datos, por lo tanto, también son objeto de ajuste. Los aspectos a revisar son:
Herramientas de optimización (trace)
Una herramienta de optimización o trace permite ver lo que se está ejecutando en un determinado momento y también visualizar el historial de las consultas que se van solicitando. Sirve para monitorear las sentencias más costosas o habituales y los datos a los que acceden las mismas. Puede automatizar recomendaciones, y por ello no considera el plan de ejecución. Sus utilidades son: