SQL : Ce qu’il ne faut pas faire

Module S8

Dalibo SCOP

24.12

18 décembre 2024

Sur ce document

Formation Module S8
Titre SQL : Ce qu’il ne faut pas faire
Révision 24.12
PDF https://dali.bo/s8_pdf
EPUB https://dali.bo/s8_epub
HTML https://dali.bo/s8_html
Slides https://dali.bo/s8_slides
TP https://dali.bo/s8_tp
TP (solutions) https://dali.bo/s8_solutions

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 13 à 17.

SQL : Ce qu’il ne faut pas faire

PostgreSQL

Des mauvaises pratiques

  • Modélisation
  • Écriture de requêtes
  • Conception de l’application

Problèmes de modélisation

  • Rappels sur le modèle relationnel
  • Formes normales
  • Atomicité !

Que veut dire « relationnel » ?

  • PostgreSQL est un SGBD-R, un système de gestion de bases de données relationnel
  • Le schéma est d’une importance capitale
  • « Relationnel » n’est pas « relation entre tables »
  • Les tables SONT les relations (entre attributs)

Quelques rappels sur le modèle relationnel

  • Le but est de modéliser un ensemble de faits
  • Le modèle relationnel a été introduit à l’époque des bases de données hiérarchiques
    • pointeur : incohérence à terme
    • formalisme : relations, modélisation évitant les incohérences suite à modification
    • formes normales
  • Un modèle n’est qu’un modèle : il ne traduit pas la réalité, simplement ce qu’on souhaite en représenter
  • Identifier rapidement les problèmes les plus évidents

Formes normales

Il existe une définition mathématique précise de chacune des 7 formes normales.

  • La troisième forme normale peut toujours être atteinte
  • La forme suivante (forme normale de Boyce-Codd, ou FNBC) ne peut pas toujours être atteinte
  • La cible est donc habituellement la 3FN
  • Chris Date :
    • « Chaque attribut dépend de la clé, de TOUTE la clé, et QUE de la clé »
    • « The key, the whole key, nothing but the key »

Atomicité

  • Un attribut (colonne) doit être atomique :

    • Modifier l’attribut sans en toucher un autre
    • Donnée correcte (délicat !)
    • Recherche efficace : accédé en entier dans une clause WHERE
  • Non respect = violation de la première forme normale

Atomicité - mauvais exemple

Immatriculation Modèle Caractéristiques
NH-415-DG twingo 4 roues motrices,toit ouvrant, climatisation
EO-538-WR clio boite automatique,abs,climatisation
INSERT INTO voitures
VALUES ('AD-057-GD','clio','toit ouvrant,abs');

Atomicité - propositions

  • Champs dédiés :
    Column      |  Type   |            Description
----------------+---------+------------------------------------
immatriculation | text    | Clé primaire
modele          | text    |
couleur         | color   | Couleur vehicule (bleu,rouge,vert)
abs             | boolean | Option anti-blocage des roues
type_roue       | boolean | tole/aluminium
motricite       | boolean | 2 roues motrices / 4 roues motrices
  • Plusieurs valeurs : contrainte CHECK/enum/table de référence

  • Beaucoup de champs : clé/valeur (plusieurs formes possibles)

Contraintes absente

  • Parfois (souvent ?) ignorées pour diverses raisons :
    • faux gains de performance
    • flexibilité du modèle de données
    • compatibilité avec d’autres SGBD (MySQL/MyISAM…)
    • commodité de développement

Conséquences de l’absence de contraintes

  • Conséquences
    • problèmes d’intégrité des données
    • fonctions de vérification de cohérence des données
  • Les contraintes sont utiles à l’optimiseur :
    • déterminent l’unicité des valeurs
    • éradiquent des lectures de tables inutiles sur des LEFT JOIN
    • utilisent les contraintes CHECK pour exclure une partition

Suspension des contraintes le temps d’une transaction

  • Solution :
    • contraintes DEFERRABLE !

Stockage Entité-Clé-Valeur

  • Entité-Attribut-Valeur (ou Entité-Clé-Valeur)
  • Quel but ?
    • flexibilité du modèle de données
    • adapter sans délai ni surcoût le modèle de données
  • Conséquences :
    • création d’une table : identifiant / nom_attribut / valeur
    • requêtes abominables et coûteuses

Stockage Entité-Clé-Valeur : exemple

Comment lister tous les DBA ?

id_pers nom_attr val_attr
1 nom Prunelle
1 prenom Léon
1 telephone 0123456789
1 fonction dba

Stockage Entité-Clé-Valeur : requête associée

SELECT id, att_nom.val_attr       AS nom,
           att_prenom.val_attr    AS prenom,
           att_telephone.val_attr AS tel
FROM personnes p
JOIN personne_attributs AS att_nom
 ON (p.id=att_nom.id_pers AND att_nom.nom_attr='nom')
JOIN personne_attributs AS att_prenom
 ON (p.id=att_prenom.id_pers AND att_prenom.nom_attr='prenom')
JOIN personne_attributs AS att_telephone
 ON (p.id=att_telephone.id_pers AND att_telephone.nom_attr='telephone')
JOIN personne_attributs AS att_fonction
 ON (p.id=att_fonction.id_pers AND att_fonction.nom_attr='fonction')
WHERE att_fonction.val_attr='dba';

Stockage Entité-Clé-Valeur, hstore, JSON

  • Solutions :
    • revenir sur la conception du modèle de données
    • utiliser un type de données plus adapté : hstore, jsonb
  • On économise jointures et place disque.

Attributs multicolonnes

  • Pourquoi
    • stocker plusieurs attributs pour une même ligne
    • exemple : les différents numéros de téléphone d’une personne
  • Pratique courante
    • ex : telephone_1, telephone_2
  • Conséquences
    • et s’il faut rajouter encore une colonne ?
    • maîtrise de l’unicité des valeurs ?
    • requêtes complexes à maintenir
  • Solutions
    • créer une table dépendante
    • ou un type tableau

Nombreuses lignes de peu de colonnes

  • Énormément de lignes, peu de colonnes
    • Cas typique : séries temporelles
  • Volumétrie augmentée par les entêtes
  • Regrouper les valeurs dans un ARRAY ou un type composite
  • Partitionner

Tables aux très nombreuses colonnes

Tables à plusieurs dizaines, voire centaines de colonnes :

  • Les entités sont certainement trop grosses dans la modélisation
  • Il y a probablement dépendance entre certaines colonnes (Only the key)
  • On accède à beaucoup d’attributs inutiles (tout est stocké au même endroit)

Choix d’un type numérique

  • Pour : représenter des valeurs décimales
  • Pratique courante :
    • real ou double (float)
    • money
    • … erreurs d’arrondis !
  • Solution :
    • numeric pour les calculs précis (financiers notamment)

Colonne de type variable

Plus rarement, on rencontre aussi :

  • Une colonne de type varchar contenant
    • quelquefois un entier
    • quelquefois une date
    • un NULL
    • une chaîne autre
    • etc.
  • À éviter comme la peste !
  • Plusieurs sens = plusieurs champs

Problèmes courants d’écriture de requêtes

  • Utilisation de NULL
  • Ordre implicite des colonnes
  • Requêtes spaghetti
  • Moteur de recherche avec LIKE

NULL

  • NULL signifie habituellement :
    • Valeur non renseignée
    • Valeur inconnue
  • Absence d’information
  • Une table remplie de NULL est habituellement signe d’un problème de modélisation.
  • NOT NULL recommandé

Ordre implicite des colonnes

  • Objectif
    • s’économiser d’écrire la liste des colonnes dans une requête
  • Problèmes
    • si l’ordre des colonnes change, les résultats changent
    • résultats faux
    • données corrompues
  • Solutions
    • nommer les colonnes impliquées

Code spaghetti

Le problème est similaire à tout autre langage :

  • Code spaghetti pour le SQL
    • Écriture d’une requête à partir d’une autre requête
    • Ou évolution d’une requête au fil du temps avec des ajouts
  • Non optimisable
  • Vite ingérable
    • Ne pas la patcher !
    • Ne pas hésiter à reprendre la requête à zéro, en repensant sa sémantique
    • Souvent, un changement de spécification est un changement de sens, au niveau relationnel, de la requête

Recherche textuelle

  • Objectif
    • ajouter un moteur de recherche à l’application
  • Pratique courante
    • utiliser l’opérateur LIKE
  • Problèmes
    • requiert des index spécialisés
    • recherche uniquement le terme exact
  • Solutions
    • pg_trgm
    • Full Text Search

Conclusion

  • La base est là pour vous aider
  • Le modèle relationnel doit être compris et appliqué
  • Avant de contourner un problème, chercher s’il n’existe pas une fonctionnalité dédiée

Quiz

Travaux pratiques

Normalisation de schéma

Entité-clé-valeur

Indexation de champs tableau

Pagination et index

Clauses WHERE et pièges

Travaux pratiques (solutions)


  1. Situation où deux sessions ou plus modifient des données en tables au même moment.↩︎