301 votes

Pourquoi le SELECT * est-il considéré comme nuisible ?

Pourquoi la SELECT * mauvaise pratique ? N'y aurait-il pas moins de code à modifier si l'on ajoutait une nouvelle colonne ?

Je comprends que SELECT COUNT(*) est un problème de performance sur certaines bases de données, mais qu'en est-il si vous voulez vraiment toutes les colonnes ?

33 votes

SELECT COUNT(*) être mauvais, c'est incroyablement vieux et dépassé . Pour plus d'informations sur SELECT * - voir : stackoverflow.com/questions/1960036/

9 votes

SELECT COUNT(*) donne une réponse différente de celle de SELECT COUNT(SomeColumn) sauf si la colonne est une colonne NOT NULL. Et l'optimiseur peut donner SELECT COUNT(*) traitement spécial - et c'est généralement le cas. Il convient également de noter que WHERE EXISTS(SELECT * FROM SomeTable WHERE ...) fait l'objet d'un traitement particulier.

0 votes

352voto

Dave Markle Points 44637

Il y a en réalité trois raisons principales :

  • Inefficacité dans le transfert des données vers le consommateur. Lorsque vous effectuez un SELECT *, vous récupérez souvent plus de colonnes de la base de données que ce dont votre application a réellement besoin pour fonctionner. De ce fait, davantage de données doivent être transférées du serveur de base de données au client, ce qui ralentit l'accès et augmente la charge sur vos machines, tout en prenant plus de temps pour circuler sur le réseau. Cela est particulièrement vrai lorsque quelqu'un ajoute de nouvelles colonnes aux tables sous-jacentes qui n'existaient pas et n'étaient pas nécessaires lorsque les consommateurs originaux ont codé leur accès aux données.

  • Problèmes d'indexation. Prenons l'exemple d'un scénario dans lequel vous souhaitez optimiser les performances d'une requête. Si vous utilisez * et que la requête renvoie plus de colonnes que vous n'en avez besoin, le serveur devra souvent exécuter des méthodes plus coûteuses pour récupérer vos données qu'il ne le ferait autrement. Par exemple, vous ne pourriez pas créer un index couvrant simplement les colonnes de votre liste SELECT, et même si vous le faisiez (en incluant toutes les colonnes [ trembler ), le prochain utilisateur qui ajoutera une colonne à la table sous-jacente amènera l'optimiseur à ignorer votre index couvrant optimisé, et vous constaterez probablement que les performances de votre requête chuteront de manière substantielle sans raison apparente.

  • Problèmes de reliure. Lorsque vous effectuez un SELECT *, il est possible de récupérer deux colonnes du même nom dans deux tables différentes. Cela peut souvent faire planter votre consommateur de données. Imaginez une requête qui joint deux tables, toutes deux contenant une colonne appelée "ID". Comment un consommateur pourrait-il savoir laquelle est laquelle ? SELECT * peut également perturber les vues (du moins dans certaines versions de SQL Server) lorsque les structures des tables sous-jacentes changent la vue n'est pas reconstruite, et les données qui reviennent peuvent être absurdes . Et le pire, c'est que vous pouvez prendre soin de nommer vos colonnes comme vous le souhaitez, mais le prochain venu n'aura aucun moyen de savoir qu'il doit s'inquiéter de l'ajout d'une colonne qui entrera en conflit avec vos noms déjà élaborés.

Mais tout n'est pas si noir pour SELECT *. Je l'utilise généreusement pour ces cas d'utilisation :

  • Requêtes ad hoc. Lorsque j'essaie de déboguer quelque chose, en particulier à partir d'une table étroite que je ne connais peut-être pas, SELECT * est souvent mon meilleur ami. Il m'aide à voir ce qui se passe sans avoir à faire une tonne de recherches sur les noms des colonnes sous-jacentes. Plus les noms de colonnes sont longs, plus c'est un avantage.

  • Lorsque * signifie "une rangée". Dans les cas d'utilisation suivants, SELECT * convient parfaitement, et les rumeurs selon lesquelles il s'agit d'un obstacle à la performance ne sont que des légendes urbaines qui ont pu avoir une certaine validité il y a de nombreuses années, mais qui n'en ont plus aujourd'hui :

    SELECT COUNT(*) FROM table;

    dans ce cas, * signifie "compter les lignes". Si vous utilisiez un nom de colonne au lieu de * , il compterait les lignes où la valeur de cette colonne n'est pas nulle . COUNT(*), à mon avis, met bien en évidence le fait que l'on compte rangs et vous évitez les cas étranges causés par l'élimination des NULLs de vos agrégats.

    Il en va de même pour ce type de requête :

    SELECT a.ID FROM TableA a
    WHERE EXISTS (
        SELECT *
        FROM TableB b
        WHERE b.ID = a.B_ID);

    dans toute base de données digne de ce nom, * signifie simplement "une ligne". Ce que vous mettez dans la sous-requête n'a pas d'importance. Certaines personnes utilisent l'identifiant de b dans la liste SELECT, ou le nombre 1, mais ces conventions n'ont aucun sens. Ce que vous voulez dire, c'est "compter la ligne", et c'est ce que signifie *. La plupart des optimiseurs de requêtes sont suffisamment intelligents pour le savoir. (Bien que pour être honnête, je n'ai que savoir SQL Server et Oracle).

20 votes

L'utilisation de "SELECT id,name" est aussi susceptible que "SELECT *" de sélectionner deux colonnes du même nom dans deux tables différentes lors de l'utilisation de jointures. Le fait de préfixer le nom de la table résout le problème dans les deux cas.

1 votes

Je sais que c'est plus ancien, mais c'est ce que j'ai trouvé en cherchant sur Google, alors je pose la question. "Quand * signifie "une rangée". Dans les cas d'utilisation suivants, SELECT * convient parfaitement, et les rumeurs selon lesquelles il s'agit d'un obstacle à la performance ne sont que des légendes urbaines..." Avez-vous des références à ce sujet ? Est-ce que cette déclaration est due au fait que le matériel est plus puissant (si c'est le cas, cela ne signifie pas qu'il n'est pas inefficace, mais simplement que vous êtes moins susceptible de le remarquer). Je n'essaie pas de faire des suppositions, je me demande simplement d'où vient cette affirmation.

6 votes

En ce qui concerne les références, vous pouvez examiner les plans de requête - ils sont identiques dans les cas où vous avez un "*" dans la sous-requête et dans les cas où vous sélectionnez une colonne. Ils sont identiques parce que l'optimiseur basé sur les coûts "reconnaît" que sémantiquement, vous parlez de n'importe quelle ligne qui satisfait aux critères - ce n'est pas une question de matériel ou de vitesse.

98voto

OMG Ponies Points 144785

Le caractère astérisque, "*", dans l'instruction SELECT est une abréviation pour toutes les colonnes de la ou des tables concernées par la requête.

Performance

En * La sténographie peut être plus lente parce que

  • Tous les champs ne sont pas indexés, ce qui oblige à effectuer un balayage complet de la table, moins efficace.
  • Ce que vous sauvegardez pour l'envoyer SELECT * sur le fil risque un balayage complet de la table
  • Renvoyer plus de données que nécessaire
  • Le renvoi des colonnes suivantes à l'aide d'un type de données de longueur variable peut entraîner une surcharge de recherche.

Maintenance

Lors de l'utilisation de SELECT * :

  • Une personne ne connaissant pas la base de code serait obligée de consulter la documentation pour savoir quelles colonnes sont renvoyées avant d'être en mesure d'effectuer des changements compétents. Rendre le code plus lisible, minimiser l'ambiguïté et le travail nécessaire pour les personnes qui ne connaissent pas le code permet d'économiser du temps et des efforts à long terme.
  • Si le code dépend de l'ordre des colonnes, SELECT * cachera une erreur qui risque de se produire si l'ordre des colonnes d'une table a été modifié.
  • Même si vous avez besoin de toutes les colonnes au moment où la requête est rédigée, ce ne sera peut-être plus le cas à l'avenir
  • l'utilisation complique le profilage

Conception

SELECT * est un anti-modèle :

  • L'objectif de la requête est moins évident ; les colonnes utilisées par l'application sont opaques.
  • Il enfreint la règle de modularité qui veut que l'on utilise un typage strict chaque fois que possible. Le typage explicite est presque universellement meilleur.

Quand faut-il utiliser "SELECT *" ? doit-il être utilisé ?

Il est acceptable d'utiliser SELECT * lorsqu'il y a un besoin explicite de toutes les colonnes des tables concernées, par opposition à toutes les colonnes qui existaient au moment où la requête a été écrite. La base de données développera en interne le * dans la liste complète des colonnes - il n'y a pas de différence de performance.

Sinon, il faut énumérer explicitement chaque colonne à utiliser dans la requête - de préférence en utilisant un alias de table.

23voto

Mark Byers Points 318575

Même si vous voulez sélectionner toutes les colonnes maintenant, vous ne voudrez peut-être pas sélectionner toutes les colonnes lorsque quelqu'un aura ajouté une ou plusieurs nouvelles colonnes. Si vous écrivez la requête avec SELECT * vous prenez le risque qu'à un moment donné, quelqu'un ajoute une colonne de texte qui ralentit l'exécution de votre requête, même si vous n'avez pas besoin de cette colonne.

N'y aurait-il pas moins de code à modifier en cas d'ajout d'une nouvelle colonne ?

Il est fort probable que si vous souhaitez réellement utiliser la nouvelle colonne, vous devrez de toute façon apporter de nombreuses autres modifications à votre code. Vous ne sauvegardez que , new_column - Il suffit de taper quelques caractères.

23 votes

Surtout si cette nouvelle colonne est un BLOB de trois mégaoctets.

3 votes

@Matti - Mais il est à espérer qu'ils réfléchissent davantage que ce qu'ils ont fait. "Hé, plaçons une énorme colonne BLOB sur cette table !" . (Je sais que c'est un espoir insensé, mais un homme ne peut-il pas rêver ?)

6 votes

La performance est un aspect, mais il y a souvent aussi un aspect de correction : la forme du résultat projeté avec des * peut inopinément cambiar et cela peut causer des dégâts dans l'application elle-même : les colonnes référencées par l'ordinal (par exemple sqldatareader.getstring(2)) récupèrent soudainement une valeur de différents colonne, tout INSERT ... SELECT * se brisera et ainsi de suite.

4voto

supercat Points 25534

Si vous nommez les colonnes dans une instruction SELECT, elles seront renvoyées dans l'ordre spécifié et peuvent donc être référencées en toute sécurité par un index numérique. Si vous utilisez "SELECT *", vous risquez de recevoir les colonnes dans un ordre arbitraire et vous ne pourrez donc utiliser les colonnes que par leur nom. À moins que vous ne sachiez à l'avance ce que vous voulez faire avec une nouvelle colonne ajoutée à la base de données, l'action correcte la plus probable est de l'ignorer. Si vous ignorez les nouvelles colonnes ajoutées à la base de données, il n'y a aucun avantage à les récupérer.

2 votes

"peuvent donc être référencés en toute sécurité par un index numérique", mais qui serait assez stupide pour toujours essayer de référencer une colonne par son index numérique au lieu de son nom !? C'est un anti-modèle bien pire que l'utilisation de select * dans une vue.

0 votes

@MGOwen : L'utilisation de select * et utiliser ensuite les colonnes par index serait horrible, mais l'utilisation de select X, Y, Z o select A,B,C et transmettre le lecteur de données résultant à un code qui s'attend à faire quelque chose avec les données des colonnes 0, 1 et 2 semble être un moyen parfaitement raisonnable de permettre au même code d'agir sur X,Y,Z ou A,B,C. Il convient de noter que les indices des colonnes dépendent de leur emplacement dans l'instruction SELECT, plutôt que de leur ordre dans la base de données.

3voto

Andrew Lewis Points 3101

Dans de nombreuses situations, SELECT * provoquera des erreurs au moment de l'exécution de votre application, plutôt qu'au moment de la conception. Il cache la connaissance des changements de colonnes ou des mauvaises références dans vos applications.

3 votes

En quoi le fait de nommer les colonnes peut-il être utile ? Dans SQL Server, les requêtes existantes, intégrées dans du code ou des SP, ne se plaindront pas avant d'être exécutées, même si vous avez nommé les colonnes. Les nouvelles requêtes échoueront lorsque vous les testerez, mais vous devrez souvent rechercher les SP affectés par des changements de table. À quel type de situations faites-vous référence et qui seraient détectées au moment de la conception ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X