Quiz : Postgres en profondeur, partie 2
SQL d'acier ou SQL en mousse ?
Partie 2 sur 2. Retour à la partie 1
Bienvenue dans la deuxième partie de mon quiz PostgreSQL approfondi !
Ce quiz explore un mélange de fonctionnalités familières et méconnues de PostgreSQL, ainsi que ses pièges classiques : JOIN, NULL, SQL ANSI, transactions, fonctionnement interne, indexation, échantillonnage de données… et plus encore !
Bonne chance ! 🍀
Laquelle de ces expressions n’est pas ❌ une expression JOIN valide dans PostgreSQL ?
Vous connaissiez le CROSS JOIN, n’est-ce pas ?
Est-ce que le JOIN ALL vous a fait penser à une autre opération, UNION ALL ?
La réponse ici est JOIN ALL ❌.
Les types de JOIN corrects sont :
INNER JOIN(le JOIN par défaut)LEFT JOIN(ouLEFT OUTER JOIN)RIGHT JOIN(ouRIGHT OUTER JOIN)FULL JOIN(ouFULL OUTER JOIN)CROSS JOIN(le produit cartésien, à moins qu’une clauseWHEREultérieure ne le filtre)
À part l’option “Dépend des effets de bord”, que se passe-t-il après une erreur ?
BEGIN;UPDATE students SET status = 'alumni' WHERE grade = 12;UPDATE students SET graduation_date = CURRENT_DATE WHERE grade = 12;UPDATE students SET grade = 'GRADUATED'; -- 🚨 Error: type mismatchCOMMIT;Lorsqu’une erreur survient ici :
- La transaction entière est annulée (rollback)
- Aucune modification n’est validée
- La transaction est marquée comme échouée
Pour effectuer une validation partielle :
BEGIN;UPDATE ...;SAVEPOINT my_save;UPDATE ...; -- ErrorROLLBACK TO my_save;COMMIT;Quelle condition ON PostgreSQL peut-il utiliser pour un HASH JOIN ?
SELECT *FROM students aJOIN grades bON /* What goes here? ⁉ */;Une jointure par hachage (hash join) est possible avec une condition d’égalité (=) dans la clause ON.
=est la forme de prédicat clé pour les hash joins>et>=ne sont pas des prédicats de hash joinHASH JOINn’est pas une syntaxe valide dans PostgreSQL
Le planificateur peut tout de même choisir une boucle imbriquée (nested loop) ou une jointure par fusion (merge join) selon la taille des tables, les statistiques, les index et les paramètres de mémoire.
Comment spécifier un nom de colonne contenant un point ?
CREATE TABLE teachers ( id INT GENERATED BY DEFAULT AS IDENTITY, first.name TEXT, -- How do you include the column: first.name? salary NUMERIC);PostgreSQL utilise des doubles guillemets pour délimiter les identifiants :
- Doubles guillemets
"..."pour les identifiants (noms de colonnes, noms de tables) - Guillemets simples
'...'pour les chaînes de caractères littérales - La forme
first.nameest interprétée commenom_table.nom_colonne
Sans guillemets, un point dans un nom de colonne serait interprété comme un séparateur schéma/table ! De plus, tous les identifiants non entourés de guillemets sont convertis en minuscules par défaut.
Afin de limiter les mauvaises surprises, il est préférable d’utiliser le snake_case et d’éviter les caractères spéciaux.
Quelle est la syntaxe valide pour échantillonner aléatoirement 10 % des étudiants ?
Celui-ci est délicat ! Il comporte environ 6 pièges, dont certains incluent :
- Description de haut niveau + fragments de syntaxe. Teste comment vous adaptez et assemblez des informations incomplètes.
- Nécessite une connaissance familière de la syntaxe
TABLESAMPLE, car aucune des optionsTABLESAMPLEn’utilise la syntaxe correcte ! (Sinistre ! Je sais ! Continuez, je crois en vous !!! ❤️) ROW_NUMBER() OVER (ORDER BY RAND())etORDER BY RANDOM() > 10sont d’autres fausses pistes. Ils ont l’air corrects, mais ne le sont pas.RAND()n’existe pas. EtRANDOM() > 10est une expression booléenne qui sera toujours fausse puisqueRANDOM()est toujours dans la plage0.0-1.0. Autre problème,ORDER BY RANDOM() > 10trierait également sur une valeur booléenne, pas sur un nombre aléatoire. Mais ce> 10donnait l’impression qu’il pouvait s’agir d’un pourcentage, n’est-ce pas ?BERNOULLIest valide, cependantSAMPLETABLEne l’est pas.WHERE RANDOM() >= 0.1est un piège !RANDOM()renvoie une valeur dans la plage0.0 <= x < 1.0, donc>= 0.1renverrait environ 90 % des lignes, pas 10 %.
En ce qui concerne la méthode TABLESAMPLE, PostgreSQL prend en charge deux méthodes d’échantillonnage :
BERNOULLI: Chaque ligne a une probabilité égaleSYSTEM: Échantillonnage au niveau des blocs (plus rapide mais moins aléatoire)
Pour en savoir plus sur l’échantillonnage, consultez cet article de Render.
Exemple :
-- Sample 10% of rowsSELECT * FROM students TABLESAMPLE BERNOULLI (10);
-- For repeatable results, use REPEATABLE:SELECT * FROM studentsTABLESAMPLE BERNOULLI (10) REPEATABLE (42);Il convient également de mentionner que TABLESAMPLE a été signalé comme n’étant pas très aléatoire. Si vous avez besoin d’un échantillon de taille fixe plus aléatoire, envisagez d’utiliser ORDER BY RANDOM() LIMIT 10. Mais attention, cela renvoie 10 lignes, pas 10 %, et peut être lent sur de grandes tables.
Il existe également des extensions tierces qui fournissent de meilleures méthodes d’échantillonnage aléatoire, mais cela sort du cadre de ce quiz ! 😅
Que fait cette incantation ?
CREATE INDEX idx_active_studentsON students(last_name)WHERE status = 'active';Cette astuce s’appelle un Partial Index (index partiel).
Ils sont utiles pour réduire l’utilisation du disque et accélérer les requêtes lorsqu’un seul sous-ensemble de lignes est généralement interrogé.
Le planificateur peut envisager cet index s’il peut prouver que les conditions de la requête impliquent status = 'active'. Une correspondance textuelle exacte n’est pas toujours nécessaire, mais ces vérifications sont limitées : une condition paramétrée peut ne pas établir le prédicat lors de la planification. Être éligible ne garantit pas que l’index sera choisi.
Rappel : Postgres ne supporte pas les ‘query hints’ (indices de requête) comme d’autres RDBMS. Le planificateur de requête décidera quand utiliser le ou les index appropriés.
Que fait EXPLAIN ANALYZE pour les instructions UPDATE ?
EXPLAIN ANALYZEUPDATE studentsSET grade = grade + 1WHERE status = 'active';EXPLAIN ANALYZE exécute réellement la requête ! Soyez prudent lors de l’analyse d’une opération d’écriture, plus précisément les instructions UPDATE, DELETE et INSERT. Vous devrez peut-être effectuer des opérations de nettoyage après chaque EXPLAIN ANALYZE pour obtenir des résultats reproductibles.
Meilleures pratiques :
- Utilisez
EXPLAIN(sans ANALYZE) pour UPDATE/DELETE/INSERT - Enveloppez les modifications dans des transactions :
BEGIN;EXPLAIN ANALYZE ...;ROLLBACK;Bien joué ! Vous avez exploré en profondeur plusieurs facettes de PostgreSQL ! 🐘
J’espère que vous avez appris quelque chose de nouveau, ou au moins que vous avez obtenu un score digne de ce nom ! 🏆
