Identifier les composants de traitement des requêtes
Il existe quatre phases distinctes pour exécuter la requête. Dans l’ordre d’exécution, ces phases sont les suivantes :
- Analyse
- Transformation (module de réécriture)
- Planification
- Exécution
L’analyseur
L’analyseur est chargé de vérifier que la syntaxe de la chaîne de requête est valide. L’analyseur est constitué de deux éléments principaux :
- gram.y, qui est constitué d’un ensemble de règles de grammaire et d’actions correspondantes.
- scan.1, l’analyseur lexical qui reconnaît les identificateurs et les mots clés SQL. Chaque mot clé ou identificateur déclenche la création et la remise d’un jeton à l’analyseur.
L’analyseur génère une arborescence de requêtes, qui sépare la requête en parties identifiables pour comprendre quelles tables sont impliquées, quels filtres ont été appliqués, etc. Les composants de l’arborescence de requêtes sont les suivants :
- Type de commande : SELECT, INSERT, UPDATE ou DELETE.
- Entrée de table de plage (RTE) : liste de relations, de tables
ie
, de sous-requêtes, de résultats de jointures, etc. Dans une instruction SELECT, ces éléments apparaissent après le mot clé FROM. - Relation de résultat : la relation de résultat pour les commandes INSERT, UPDATE et DELETE est la table ou la vue où les modifications doivent prendre effet.
- Liste cible : résultats de la requête, situés entre les mots clés SELECT et FROM. Les commandes DELETE ne produisent pas de résultat, de sorte que le planificateur ajoute une entrée spéciale pour permettre à l’exécuteur de trouver la ligne à supprimer. Les commandes INSERT identifient les nouvelles lignes qui doivent entrer dans la relation de résultat. Pour les commandes UPDATE, la liste cible décrit les nouvelles lignes qui doivent remplacer les anciennes.
- Qualification : valeur booléenne qui spécifie si l’opération de la ligne de résultat finale doit être exécutée ou non. Elle correspond à la clause WHERE d’une instruction SQL.
- Arborescence des jointures : cette arborescence peut être une liste des éléments FROM. Les jointures peuvent être effectuées dans n’importe quel ordre, ou dans un ordre spécifique, comme les jointures externes en premier.
- Autres : éléments qui ne sont pas pertinents à ce stade, comme la clause ORDER BY.
Module de réécriture
La sortie de l’analyseur est passée au processus transformation ou réécriture, sauf si une erreur est détectée. Dans ce cas, un message d’erreur est retourné.
Le module de réécriture réécrit le texte de la requête en y appliquant des règles. Le module de réécriture prend en compte les règles, puis passe la requête modifiée au planificateur de requêtes. La sécurité au niveau des lignes est implémentée lors de cette phase.
Par exemple, les règles sur SELECT sont toujours appliquées en dernière étape, notamment pour les requêtes INSERT, UPDATE et DELETE. Les règles signifient également que les requêtes UPDATE ne remplacent pas les lignes existantes. Les nouvelles lignes sont insérées et les anciennes lignes sont masquées. Une fois la transaction validée, le processus de vidage peut supprimer la ligne masquée.
Planificateur
Le travail du planificateur consiste à accepter les règles de requête et à comprendre laquelle des méthodes d’exécution de la requête est la plus rapide.
Le planificateur crée une arborescence de plan avec des nœuds représentant des opérations physiques effectuées sur les données.
PostgreSQL utilise un optimiseur de requête basé sur les coûts afin de trouver le plan optimal pour une requête. Le planificateur évalue différents plans d’exécution et estime la quantité de ressources nécessaires, comme les cycles processeur, les opérations d’E/S, etc. Cette estimation est ensuite convertie en unités appelées coût du plan. C’est le plan dont le coût est le plus bas qui est sélectionné.
Toutefois, au fur et à mesure que le nombre de jointures augmente, le nombre de plans possibles augmente de façon exponentielle. L’évaluation de chaque plan possible devient impossible, même pour les requêtes relativement simples. L’heuristique et les algorithmes sont utilisés pour limiter le nombre de plans possibles. Résultat, le plan sélectionné risque de ne pas être le plan optimal. Toutefois, il est presque optimal et est sélectionné dans un délai raisonnable.
Le coût correspond à l’estimation la plus juste du planificateur. L’objectif de l’estimation des coûts est de comparer différents plans d’exécution pour une même requête dans des conditions identiques. Le planificateur utilise des statistiques collectées à partir des tables et des lignes afin de produire des estimations de coûts pour les requêtes. Pour que les estimations des coûts soient justes, les statistiques doivent être à jour.
Statistiques à jour
Le composant planificateur de l’optimiseur de requête utilise des statistiques sur les tables et les lignes afin de produire des estimations de coûts justes.
ANALYZE collecte des statistiques sur les tables de base de données et stocke les résultats dans le catalogue système pg_statistic. Vous devez exécuter ANALYZE si :
- Vous avez désactivé le vidage automatique (qui, normalement, analyse automatiquement les tables)
- Vous avez désactivé le vidage automatique et n’avez pas exécuté ANALYZE récemment
- L’un des deux, et il y a de nombreuses instructions INSERTS, UPDATES ou DELETE.
Les estimations des coûts sont basées sur des statistiques à jour. Si les statistiques sont obsolètes, un plan inefficace risque d’être choisi. Lorsqu’aucun paramètre n’est passé à ANALYZE, chaque table de la base de données est examinée.
La syntaxe pour ANALYZE est la suivante :
ANALYZE [ VERBOSE ] [ ***table*** [ ( ***column*** [, ...] ) ] ]
VERBOSE affiche les messages de progression pour afficher la table à analyser, ainsi que certaines statistiques.
Planifiez l’exécution quotidienne de VACUUM et ANALYZE pendant une période de faible utilisation. ANALYZE peut s’exécuter parallèlement à d’autres activités, car il ne nécessite que l’application d’un verrou de lecture sur la table cible.
Exécuteur
Cette phase prend le plan créé par le planificateur et le traite de manière récursive pour extraire l’ensemble de lignes nécessaire. Chaque fois qu’un nœud de plan est appelé, l’exécuteur doit remettre une ligne ou afficher un message indiquant qu’il a terminé.
L’exécuteur évalue les quatre types de requêtes SQL :
- SELECT
- INSERT
- UPDATE
- DELETE
Pour SELECT, l’exécuteur retourne chaque ligne au client sous la forme d’un jeu de résultats.
Pour INSERT, chaque ligne retournée est insérée dans la table spécifiée. Cette tâche est effectuée dans un nœud de plan spécial de niveau supérieur appelé ModifyTable.
Pour UPDATE, chaque ligne calculée inclut toutes les valeurs de colonne mises à jour, ainsi que l’ID de la ligne cible. Les données sont envoyées à un nœud ModifyTable, qui crée une ligne mise à jour et marque l’ancienne ligne comme étant supprimée.
Pour DELETE, la seule colonne retournée par le plan est l’ID de ligne. Le nœud ModifyTable utilise l’ID de ligne pour marquer la ligne comme étant supprimée.