Utilisation avec une fonction retournant un ensemble
clause LATERAL optionnelle
Utilité :
extraire les données d’un tableau ou d’une structure
JSON sous la forme tabulaire
utiliser une fonction métier qui retourne un ensemble X selon un
ensemble Y fourni
LATERAL : exemple avec une
fonction
SELECT titre, top_5_messages.date_publication, top_5_messages.extraitFROM sujets, get_top_5_messages(sujet_id) AS top_5_messagesORDERBY sujets.date_modification DESCLIMIT25;
Common Table Expressions
Common Table Expressions
clauses WITH et WITH RECURSIVE
Utilité :
factoriser des sous-requêtes
CTE et SELECT
Utilité
factoriser des sous-requêtes
améliorer la lisibilité d’une requête
CTE et SELECT : exemple
WITH resultat AS (/* requête complexe */)SELECT*FROM resultatWHERE nb <5;
CTE et SELECT : syntaxe
WITH nom_vue1 AS [ [ NOT ] MATERIALIZED ] (<requête pour générer la vue 1>)SELECT*FROM nom_vue1;
CTE et barrière
d’optimisation
Attention, une CTE est une barrière d’optimisation !
pas de transformations
pas de propagation des prédicats
Sauf à partir de la version 12
clause MATERIALIZED pour obtenir cette barrière
CTE en écriture
CTE avec des requêtes en modification
avec
INSERT/UPDATE/DELETE
et éventuellement RETURNING
obligatoirement exécuté sur PostgreSQL
Exemple d’utilisation :
archiver des données
partitionner les données d’une table
débugger une requête complexe
CTE en écriture : exemple
WITH donnees_a_archiver AS (DELETEFROM donnes_courantesWHEREdate<'2015-01-01'RETURNING*)INSERTINTO donnes_archiveesSELECT*FROM donnees_a_archiver;
CTE récursive
SQL permet d’exprimer des récursions
WITH RECURSIVE
Utilité :
récupérer une arborescence de menu hiérarchique
parcourir des graphes (réseaux sociaux, etc.)
CTE récursive : exemple (1/2)
WITH RECURSIVE suite AS (SELECT1AS valeurUNIONALLSELECT valeur +1FROM suiteWHERE valeur <10)SELECT*FROM suite;
CTE récursive : principe
1ère étape : initialisation de la récursion
CTE récursive : principe
récursion : la requête s’appelle elle-même
CTE récursive : exemple (2/2)
WITH RECURSIVE parcours_menu AS (SELECT menu_id, libelle, parent_id, libelle AS arborescenceFROM entrees_menuWHERE libelle ='Terminal'AND parent_id ISNULLUNIONALLSELECT menu.menu_id, menu.libelle, menu.parent_id, arborescence ||'/'|| menu.libelleFROM entrees_menu menuJOIN parcours_menu parentON (menu.parent_id =parent.menu_id))SELECT*FROM parcours_menu;
Concurrence d’accès
Problèmes pouvant se poser :
UPDATE perdu
lecture non répétable
Plusieurs solutions possibles
versionnement des lignes
SELECT FOR UPDATE
SERIALIZABLE
SELECT FOR UPDATE
SELECT FOR UPDATE
Utilité :
« réserver » des lignes en vue de leur mise à jour
éviter les problèmes de concurrence d’accès
SKIP LOCKED
SELECT FOR UPDATE SKIP LOCKED
PostgreSQL 9.5
Utilité :
implémente des files d’attentes parallélisables
Serializable Snapshot
Isolation
SSI : Serializable Snapshot Isolation (9.1+)
Chaque transaction est seule sur la base
Si on ne peut maintenir l’illusion
une des transactions en cours est annulée
Sans blocage
On doit être capable de rejouer la transaction
Toutes les transactions impliquées doivent être
serializable
default_transaction_isolation=serializable dans la
configuration
Conclusion
SQL est un langage très riche
Connaître les nouveautés des versions de la norme depuis 20 ans
permet de
gagner énormément de temps de développemment
mais aussi de performance
Travaux pratiques
Travaux pratiques (solutions)
La solution actuelle semble techniquement meilleure et
la solution actuelle a donc été choisie. Le wiki du projet PostgreSQL
montre que l’ordre MERGE a été étudié et qu’un certain
nombre d’aspects cruciaux n’ont pas été spécifiés, amenant le projet
PostgreSQL à utiliser sa propre version. Voir la documentation : https://wiki.postgresql.org/wiki/UPSERT#MERGE_disadvantages.↩︎