Références des nœuds

Module J6

Dalibo SCOP

24.04

17 avril 2024

Sur ce document

Formation Module J6
Titre Références des nœuds
Révision 24.04
PDF https://dali.bo/j6_pdf
EPUB https://dali.bo/j6_epub
HTML https://dali.bo/j6_html
Slides https://dali.bo/j6_slides

Licence Creative Commons CC-BY-NC-SA

Cette formation est sous licence CC-BY-NC-SA. Vous êtes libre de la redistribuer et/ou modifier aux conditions suivantes :

  • Paternité
  • Pas d’utilisation commerciale
  • Partage des conditions initiales à l’identique

Marques déposées

PostgreSQL® Postgres® et le logo Slonik sont des marques déposées par PostgreSQL Community Association of Canada.

Versions de PostgreSQL couvertes

Ce document ne couvre que les versions supportées de PostgreSQL au moment de sa rédaction, soit les versions 12 à 16.

Référence sur les nœuds d’exécution

PostgreSQL

Introduction

  • Quatre types de nœuds
    • parcours (de table, d’index, de TID, etc.)
    • jointures (Nested Loop, Sort/Merge Join, Hash Join)
    • opérateurs sur des ensembles (Append, Except, Intersect, etc.)
    • et quelques autres (Sort, Aggregate, Unique, Limit, Materialize)

Parcours

  • Ne prend rien en entrée
  • Mais renvoie un ensemble de données
    • trié ou non, filtré ou non
  • Exemples typiques
    • parcours séquentiel d’une table, avec ou sans filtrage des enregistrements produits
    • parcours par un index, avec ou sans filtrage supplémentaire

Parcours de table

  • Parcours séquentiel de la table (Sequential Scan ou Seq Scan)
    • parallélisation possible (Parallel Seq Scan)
  • Aussi appelé Full table scan par d’autres SGBD
  • La table est lue entièrement
    • même si seulement quelques lignes satisfont la requête
    • sauf pour LIMIT sans ORDER BY
  • Séquentiellement, par bloc de 8 ko
  • Optimisation : synchronize_seqscans

Parcours d’index

  • Parcours aléatoire de l’index
  • Pour chaque enregistrement correspondant à la recherche
    • parcours non séquentiel de la table (pour vérifier la visibilité de la ligne)
  • Gros gain en performance si filtre très sélectif
  • Les lignes renvoyées sont triées
  • Parallélisation possible
    • B-Tree uniquement
  • Sur d’autres SGBD : INDEX RANGE SCAN + TABLE ACCESS BY INDEX ROWID

Parcours d’index bitmap

  • Bitmap Index Scan / Bitmap Heap Scan
  • Réduire les allers-retours index <-> table
    • trouver les blocs de l’index
    • lecture des blocs intéressantde la table
  • Combiner plusieurs index en mémoire
    • nœud BitmapAnd
    • nœud BitmapOr
  • Coût de démarrage généralement important (pas intéressant avec LIMIT)
  • Parallélisation possible
  • B-Tree uniquement
  • Sensible à :
    • effective_io_concurrency

Parcours d’index seul

SELECT c1 FROM t1 WHERE c1<10
  • Avant 9.2 : PostgreSQL devait lire l’index + la table
  • À présent : le planificateur utilise la Visibility Map
    • nœud Index Only Scan
    • index B-Tree
    • index SP-GiST
    • index GiST => Types : point, box, inet, range

Parcours : autres

  • TID Scan
  • Function Scan
  • Values
  • Result

Jointures

  • Prend 2 ensembles de données en entrée
    • inner (interne)
    • outer (externe)
  • Et renvoie un seul ensemble de données
  • Exemples typiques :
    • Nested Loop, Merge Join, Hash Join

Nested Loops

Boucles imbriquées

  • Pour chaque ligne de la relation externe
    • pour chaque ligne de la relation interne
      • si la condition de jointure est avérée : émettre la ligne en résultat
  • L’ensemble externe n’est parcouru qu’une fois
  • L’ensemble interne est parcouru pour chaque ligne de l’ensemble externe
    • un index utilisable sur l’ensemble interne augmente fortement les performances !

Merge Join

Jointure d’ensembles triés

  • Trier l’ensemble interne
  • Trier l’ensemble externe
  • Tant qu’il reste des lignes dans un des ensembles
    • lire les deux ensembles en parallèle
    • si la condition de jointure est avérée : émettre la ligne
  • Parcourir les deux ensembles triés (d’où Sort-Merge Join)
  • Ne gère que les conditions avec égalité
  • Produit un ensemble résultat trié
  • Le plus rapide sur de gros ensembles de données

Hash Join

Jointure par hachage

  • Calculer le hachage de chaque ligne de l’ensemble interne
  • Tant qu’il reste des lignes dans l’ensemble externe
    • hacher la ligne lue
    • comparer ce hachage aux lignes hachées de l’ensemble interne
    • si une correspondance est trouvée : émettre la ligne
  • Ne gère que les conditions avec égalité
  • Idéal pour joindre une grande table à une petite table
  • Coût de démarrage important à cause du hachage de la table

Suppression d’une jointure

SELECT pg_class.relname, pg_class.reltuples
FROM pg_class
LEFT JOIN pg_namespace
       ON pg_class.relnamespace=pg_namespace.oid;
  • Un index unique existe sur la colonne oid de pg_namespace
  • Jointure inutile
    • sa présence ne change pas le résultat

Ordre de jointure

  • Trouver le bon ordre de jointure est un point clé dans la recherche de performances
  • Nombre de possibilités en augmentation factorielle avec le nombre de tables
  • Si petit nombre, recherche exhaustive
  • Sinon, utilisation d’heuristiques et de GEQO (geqo_threshold)
    • limite le temps de planification et l’utilisation de mémoire
    • join_collapse_limit, from_collapse_limit : limites de 8 tables

Opérations ensemblistes

  • Prend un ou plusieurs ensembles de données en entrée
  • Et renvoie un ensemble de données
  • Concernent principalement les requêtes sur des tables partitionnées ou héritées
  • Exemples typiques
    • Append
    • Intersect
    • Except

Append

  • Prend plusieurs ensembles de données
  • Sortie non triée
  • Utilisation :
    • tables héritées (dont partitionnement)
    • UNION ALL et des UNION
    • NB : UNION sans ALL élimine les doublons (tri !)
  • Opération parallélisable (v11)

MergeAppend

  • Append avec optimisation
  • Sortie triée
  • Utilisation :
    • UNION ALL , partitionnement/héritage
    • avec parcours triés
    • idéal avec LIMIT

Autres nœuds

  • Nœud HashSetOp Except
    • EXCEPT et EXCEPT ALL
  • Nœud HashSetOp Intersect
    • INTERSECT et INTERSECT ALL

Divers

  • Prend un ensemble de données en entrée
  • Et renvoie un ensemble de données
  • Exemples typiques
    • Sort
    • Aggregate
    • Unique
    • Limit
    • InitPlan, SubPlan

Tris

  • Sort
  • Incremental Sort

Sort

  • Utilisé pour le ORDER BY
    • Mais aussi DISTINCT, GROUP BY, UNION
    • Les jointures de type Merge Join
  • Gros délai de démarrage
  • Trois types de tri
    • en mémoire, tri quicksort
    • en mémoire, tri top-N heapsort (si LIMIT)
    • sur disque

Incremental Sort

  • Utilisé lorsqu’un index existe sur les premières colonnes du tri
    • ORDER BY, DISTINCT, GROUP BY, UNION
    • Les jointures de type Merge Join
  • Délai de démarrage réduit

Aggregate

  • Agrégat complet
  • Pour un seul résultat

HashAggregate

  • Hachage de chaque n-uplet de regroupement (GROUP BY)
  • Accès direct à chaque n-uplet pour appliquer fonction d’agrégat
  • Intéressant si l’ensemble des valeurs distinctes tient en mémoire, dangereux sinon

GroupAggregate

  • Reçoit des données déjà triées
  • Parcours des données
    • regroupement du groupe précédent arrivé à une donnée différente

Unique

  • Reçoit des données déjà triées
  • Parcours des données
    • renvoi de la donnée précédente une fois arrivé à une donnée différente
  • Résultat trié

Limit

  • Limiter le nombre de résultats renvoyés
  • Utilisation :
    • LIMIT et OFFSET dans une requête SELECT
    • fonctions min() et max() quand il n’y a pas de clause WHERE et qu’il y a un index
  • Le nœud précédent sera de préférence un nœud dont le coût de démarrage est peu élevé (Seq Scan, Nested Loop)

Memoize

  • Apparu en version 14
  • Cache de résultat
  • Utilisable par la table interne des Nested Loop
  • Utile si :
    • peu de valeurs distinctes dans l’ensemble interne
    • beaucoup de valeurs dans l’ensemble externe
    • peu de correspondance entre les deux ensembles
  • Paramètres : work_mem hash_mem_multiplier