Identificación de los componentes de procesamiento de consultas
Hay cuatro fases independientes para ejecutar la consulta. En orden de ejecución, estas fases son:
- Análisis
- Transformación (sistema de reescritura)
- Planificación
- Ejecución
Analizador
El analizador es responsable de comprobar la cadena de consulta para verificar que la sintaxis es válida. El analizador tiene dos partes principales:
- gram.y: se compone de un conjunto de reglas gramaticales y las acciones correspondientes.
- scan.1 el lexer, que reconoce identificadores y palabras clave de SQL. Cada palabra clave o identificador desencadena un token que se crea y se entrega al analizador.
El analizador crea un árbol de consulta, que separa la consulta en partes identificables para comprender qué tablas están implicadas, qué filtros se aplicaron, etc. Las partes de un árbol de consulta son:
- Tipo de comando: SELECT, INSERT, UPDATE o DELETE.
- Entrada de tabla de rango (RTE): una lista de relaciones, tablas
ie
, subconsultas, resultados de combinaciones, etc. En una instrucción SELECT, estos elementos aparecen después de la palabra clave FROM. - Relación de resultados: la relación de resultados de los comandos INSERT, UPDATE y DELETE es la tabla o vista en la que se van a aplicar los cambios.
- Lista de destino: resultados de la consulta, identificados entre las palabras clave SELECT y FROM. Los comandos DELETE no generan un resultado, por lo que el planificador agrega una entrada especial para permitir que el ejecutor encuentre la fila que se va a eliminar. Los comandos INSERT identifican las nuevas filas que deben incluirse en la relación de resultados. En el caso de los comandos UPDATE, la lista de destino describe las filas nuevas que deben reemplazar las antiguas.
- Calificación: valor booleano que especifica si se debe ejecutar la operación para la fila de resultados final. Corresponde a la cláusula WHERE de una instrucción SQL.
- Árbol de combinación : este árbol podría ser una lista de los elementos FROM. Las combinaciones se pueden realizar en cualquier orden o en un orden específico, como las combinaciones externas.
- Otros: elementos que no son pertinentes en esta fase, como la cláusula ORDER BY.
Sistema de reescritura
La salida del analizador se pasa al proceso de transformación o reescritura, a menos que se encuentre un error, en cuyo caso se devuelve un mensaje de error.
El sistema de reescritura de consultas vuelve a escribir el texto de la consulta aplicándole reglas. El sistema de reescritura tiene en cuenta las reglas y, luego, pasa la consulta modificada al planificador de consultas. En esta fase se implementa la seguridad de nivel de fila.
Por ejemplo, las reglas de SELECT siempre se aplican como último paso, incluido para las consultas INSERT, UPDATE y DELETE. Además, con las reglas, las consultas UPDATE no sobrescriben las filas existentes, sino que se inserta una fila nueva y se oculta la anterior. Una vez confirmada la transacción, el proceso de vaciado puede quitar la fila oculta.
Planner
El trabajo del planificador consiste en tomar las reglas de consulta y comprender cuál de las distintas formas en las que puede ejecutarse la consulta es más rápida.
El planificador crea un árbol de plan, con nodos que representan operaciones físicas en los datos.
PostgreSQL usa un optimizador de consultas basado en costes para encontrar el plan óptimo para una consulta. El planificador evalúa varios planes de ejecución y calcula la cantidad de recursos necesarios, como ciclos de CPU, operaciones de E/S, etc. Después, esta estimación se convierte en unidades, lo que se conoce como coste del plan. Se selecciona el plan con el coste más bajo.
Aun así, a medida que aumenta el número de combinaciones, el número de planes posibles crece exponencialmente. Evaluar cada plan posible es una tarea inviable incluso en el caso de consultas relativamente sencillas. Para limitar el número de planes posibles, se usan la heurística y algoritmos. Como resultado, el plan seleccionado podría no ser el óptimo. De todos modos, es casi óptimo y se seleccionará en un tiempo razonable.
El coste es la mejor estimación del planificador. El propósito de la estimación de costes es comparar diferentes planes de ejecución para la misma consulta en las mismas condiciones. El planificador usa estadísticas recopiladas en tablas y filas para generar estimaciones de costes para las consultas. Para que las estimaciones de costes sean precisas, las estadísticas deben estar actualizadas.
Estadísticas actualizadas
El componente de planificador del optimizador de consultas usa estadísticas sobre las tablas y las filas para generar estimaciones de costes precisas.
El comando ANALYZE recopila estadísticas sobre las tablas de la base de datos y almacena los resultados en el catálogo del sistema pg_statistic. Debe ejecutar ANALYZE en los casos siguientes:
- Si ha deshabilitado el vaciado automático (que normalmente analiza las tablas automáticamente)
- Si ha deshabilitado el vaciado automático y no ha ejecutado ANALYZE recientemente
- Cualquiera de las anteriores, y hay muchas instrucciones INSERTS, UPDATES o DELETE.
Las estimaciones de costos dependen de estadísticas actualizadas; si están obsoletas, es posible que se elija un plan ineficaz. Cuando no se pasa ningún parámetro a ANALYZE, se examinan todas las tablas de la base de datos.
La sintaxis de ANALYZE es la siguiente:
ANALYZE [ VERBOSE ] [ ***table*** [ ( ***column*** [, ...] ) ] ]
VERBOSE muestra los mensajes de progreso para indicar qué tabla se está analizando, junto con algunas estadísticas.
Programe la ejecución diaria de VACUUM y ANALYZE durante un momento de poca utilización. ANALYZE se puede ejecutar en paralelo con otras actividades, ya que solo requiere un bloqueo de lectura en la tabla de destino.
Ejecutor
En esta fase se toma el plan que ha creado el planificador y se procesa de forma recursiva para extraer el conjunto necesario de filas. Cada vez que se llama a un nodo de plan, el ejecutor debe entregar una fila o notificar que ha finalizado.
El ejecutor evalúa los cuatro tipos de consulta SQL:
- SELECT
- INSERT
- UPDATE
- Delete
Para SELECT, el ejecutor devuelve cada fila al cliente como conjunto de resultados.
Para INSERT, cada fila devuelta se inserta en la tabla especificada. Esta tarea se lleva a cabo en un nodo de plan de nivel superior especial denominado ModifyTable.
Para UPDATE, cada fila calculada incluye todos los valores de columna actualizados, además del identificador de fila de la fila de destino. Los datos se envían a un nodo ModifyTable, que crea una fila actualizada y marca la fila antigua como eliminada.
Para DELETE, la única columna que el plan devuelve realmente es el identificador de fila. El nodo ModifyTable usa el identificador de fila para marcar la fila como eliminada.