IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

escartefigue

[Actualité] Quand utiliser SELECT *

Note : 4 votes pour une moyenne de 3,75.
par , 19/04/2023 à 16h06 (12359 Affichages)
On trouve très souvent des traitements dans lesquels les requêtes utilisent des ordres SELECT *.

Or il faut savoir que, avec SELECT *
  • on transporte des colonnes dont on n'a pas besoin, ce qui charge le réseau inutilement et pénalise les performances :
    - il est très rare qu'on ait besoin de toutes les colonnes d'une table dans un traitement,
    - si la requête utilise des jointures, toutes les colonnes de jointure sont présentes plusieurs fois ;
  • les études d'impact sont difficiles puisqu'on ne sait pas quelles sont les colonnes réellement utiles au traitement ;
  • en cas de modification de la table ou de la vue, le traitement plante ou les résultats sont erronés ;
  • les index couvrants, si présents, sont inutilisables.


Pour ces raisons, certaines entreprises interdisent purement et simplement de coder SELECT * dans un livrable !

Les seuls cas où l'on peut s'autoriser SELECT * sont les suivants :
  • requête jetable, exécutée à la volée, mais qui n'a pas vocation à être intégrée dans un livrable ;
  • cas particulier du test d'existence avec (NOT) EXISTS
    En effet, dans ce cas, le SELECT ne transporte qu'un booléen (vrai/faux), il n'y a donc pas d'inconvénient à coder SELECT *.
    Toutefois, le risque subsiste qu'un développeur ne connaissant pas cette particularité copie/colle ce code pour un autre usage, retombant ainsi dans les travers évoqués plus haut.
    C'est pourquoi, pour un test d'existence, je préfère coder SELECT 1 dans la requête corrélée.

Envoyer le billet « Quand utiliser SELECT * » dans le blog Viadeo Envoyer le billet « Quand utiliser SELECT * » dans le blog Twitter Envoyer le billet « Quand utiliser SELECT * » dans le blog Google Envoyer le billet « Quand utiliser SELECT * » dans le blog Facebook Envoyer le billet « Quand utiliser SELECT * » dans le blog Digg Envoyer le billet « Quand utiliser SELECT * » dans le blog Delicious Envoyer le billet « Quand utiliser SELECT * » dans le blog MySpace Envoyer le billet « Quand utiliser SELECT * » dans le blog Yahoo

Mis à jour 02/05/2023 à 16h25 par escartefigue (orthographe (oops !))

Catégories
Sans catégorie

Commentaires

  1. Avatar de sevyc64
    • |
    • permalink
    Ca fait plaisir de lire une telle chose.

    Il y a beaucoup de monde qui devrait lire ça, y compris certaines personnes qui se prétendent expert sql.
  2. Avatar de wchris
    • |
    • permalink
    Il y a d'autres cas où l'on peux s'en servir, par exemple dans le cas de requêtes imbriquées

    Select * from (
    Select Lbl1 "REFERENCE", val1 "VALEUR" from TABLEITEM1 where TI1TYPE='A'
    UNION
    Select Lbl2, val2 from TABLEITEM2 where TI1TYPE IN ('B', 'D')
    )
    where VALEUR between 50 and 200;

    Dans ce cas il n'y a aucun impact sur le nombre de colonnes renvoyées ni les jointures et pourtant on a utilisé *

    PS je ne sais pas si l'exemple fonctionne je ne l'ai pas testé, c'est juste une illustration
  3. Avatar de Séb.
    • |
    • permalink
    Tout à fait d'accord avec le SELECT * à n'utiliser que pour de l'exploration ou un test d'existence.

    Je me l'autorise également dans un cadre très contrôlé, où la requête maîtrise les colonnes, et pour éviter de la redite.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    WITH dataset (col1, col2, col3) AS (
        SELECT ALL col1, col2, col1 + col2
        FROM my_table
    )
    SELECT ALL *
    FROM dataset;
    J'ai déjà été confronté à des SELECT * qui ont dégradé un applicatif le jour où quelqu'un a eu la bonne idée d'ajouter une colonne BLOB contenant le binaire d'un e-mail. Les SELECT * ont généré beaucoup de trafic inutile et ont sensiblement impacté les perfs.
  4. Avatar de escartefigue
    • |
    • permalink
    Citation Envoyé par wchris
    Il y a d'autres cas où l'on peux s'en servir, par exemple dans le cas de requêtes imbriquées

    Select * from (
    Select Lbl1 "REFERENCE", val1 "VALEUR" from TABLEITEM1 where TI1TYPE='A'
    UNION
    Select Lbl2, val2 from TABLEITEM2 where TI1TYPE IN ('B', 'D')
    )
    where VALEUR between 50 and 200;

    Dans ce cas il n'y a aucun impact sur le nombre de colonnes renvoyées ni les jointures et pourtant on a utilisé *
    En effet, mais le SELECT * s'applique ici à une liste fermée de colonnes définie par la requête imbriquée, on en revient donc à la préconisation que j'ai formulée
  5. Avatar de berceker united
    • |
    • permalink
    Très bon article, il faut une suite.
    Dommage qu'il n'a pas été développé le cas du SELECT COUNT(*).
    J'ai entendu tellement de chose sur ça. En gros, c'est issu d'un bug de l'époque napoléonienne (c'est une blague hein). Le moyens de contourner le problème était de faire SELECT COUNT(1), corrigé depuis et c'est resté dans les têtes jusqu'à aujourd'hui sans vraiment savoir pourquoi.
    Ce qu'il se passe dans la tête de certain aujourd'hui c'est que COUNT(*) = COUNT(champ1,champ2,champ3,champ4,...). Je fais quand même confiance aux personnes développant les moteurs SQL qu'ils ne font pas cela.

    Quand j'en parle aujourd'hui en prouvant par A+B ça reste encore sceptique "ouais... mais... bon.... voila .... c'est pas optimisé". Explique moi ce qu'il se passe derrière un count(*) ?
    Pour embêter mes collègues je faisais exprès de mettre COUNT(8) => "ouais... mais... bon.... voila .... c'est pas optimisé..."

    Souvent, par mimétisme nous codons sans trop se poser des questions du pourquoi.
  6. Avatar de escartefigue
    • |
    • permalink
    Citation Envoyé par berceker united
    Ce qu'il se passe dans la tête de certain aujourd'hui c'est que COUNT(*) = COUNT(champ1,champ2,champ3,champ4,...).
    Quelques précisions :
    • à ma connaissance, seuls MySQL et MariaDB acceptent une liste de colonnes dans la fonction COUNT()
      pour les autres SGBD, COUNT() s'applique soit avec *, soit avec un nom de colonne unique ;
    • comme par défaut, c'est le paramètre ALL qui s'applique, utiliser SELECT COUNT(*) ou SELECT COUNT(Colonne1) produit le même résultat. En l'occurrence le nombre de lignes dans la table.
      Si par contre on utilise le paramètre DISTINCT, alors SELECT COUNT(*) et SELECT COUNT(DISTINCT Colonne1) peuvent évidemment produire un résultat différent, si Colonne1 présente la même valeur sur plusieurs lignes ;
    • le paramètre DISTINCT n'est pas applicable avec (*) ;
    • parler de "champs" est un abus de langage. Dans une table d'un SGBD relationnel, il n'y a pas de champs, il y a des colonnes. Les champs sont les zones d'un formulaire ou d'un état.
    Mis à jour 09/05/2023 à 13h23 par escartefigue
  7. Avatar de berceker united
    • |
    • permalink
    Je viens de me rappeler d'un chose dans ce que vous dite. Entre le faite de mettre une étoile ou nom de champ dans le count dans SQL Server.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    CREATE TABLE #matable(nom varchar(10))
    go
    insert into #matable (nom)values ('Diriz'),('Colombo'),(null)--nom de mes greffiers 
    
    
    select count(*) from #matable 
    select count(nom) from #matable
    Le premier résultat va retourne 3, le second 2 car le count va retourner que les valeurs non null