L'essence de la citation de ne pas optimiser prématurément est d'opter pour un code simple et direct, puis d' utiliser un profileur pour signaler les points chauds, que vous pouvez ensuite optimiser pour être efficace.
Lorsque vous utilisez select *, il est impossible de profiler, par conséquent, vous n'écrivez pas de code clair et direct et vous allez à l'encontre de l'esprit de la citation. select *
est un anti-pattern.
La sélection des colonnes n'est donc pas une optimisation prématurée. Quelques petites choses qui me viennent à l'esprit ...
- Si vous spécifiez des colonnes dans une instruction SQL, le moteur d'exécution SQL génère une erreur si cette colonne est supprimée de la table et que la requête est exécutée.
- Vous pouvez scanner plus facilement le code là où cette colonne est utilisée.
- Vous devez toujours écrire des requêtes pour ramener le moins d'informations possible.
- Comme d'autres le mentionnent, si vous utilisez l'accès à la colonne ordinale, vous ne devez jamais utiliser select *
- Si votre instruction SQL joint des tables, sélectionnez * vous donne toutes les colonnes de toutes les tables de la jointure
Le corollaire est que l'utilisation de select *
...
- Les colonnes utilisées par l'application sont opaques
- Les administrateurs de bases de données et leurs profileurs de requêtes ne sont pas en mesure d'aider les mauvaises performances de votre application
- Le code est plus fragile lorsque des changements se produisent
- Votre base de données et votre réseau souffrent car ils rapportent trop de données (E / S)
- Les optimisations du moteur de base de données sont minimes car vous ramenez toutes les données indépendamment (logique).
Ecrire du SQL correct est aussi simple que l'écriture Select *
. Donc, le vrai paresseux écrit du SQL approprié parce qu'il ne veut pas revoir le code et essayer de se souvenir de ce qu'il faisait quand il l'a fait. Ils ne veulent pas expliquer aux DBA à propos de chaque bit de code. Ils ne veulent pas expliquer à leurs clients pourquoi l'application fonctionne comme un chien.
Si votre code dépend du fait que les colonnes sont dans un ordre spécifique, votre code sera interrompu lors de modifications de la table. De plus, vous en récupérez peut-être trop dans la table lorsque vous sélectionnez *, surtout s'il y a un champ binaire dans la table.
Ce n'est pas parce que vous utilisez toutes les colonnes maintenant que quelqu'un d'autre ne va pas ajouter une colonne supplémentaire à la table.
Il ajoute également une surcharge à la mise en cache d'exécution du plan car il doit récupérer les métadonnées sur la table pour savoir quelles colonnes se trouvent dans *.
la source
L'une des raisons principales est que si jamais vous ajoutez / supprimez des colonnes de votre table, toute requête / procédure qui effectue un appel SELECT * recevra désormais plus ou moins de colonnes de données que prévu.
la source
D'une manière détournée, vous enfreignez la règle de modularité concernant l'utilisation d'un typage strict dans la mesure du possible. Explicite est presque universellement meilleur.
Même si vous avez maintenant besoin de chaque colonne de la table, d'autres pourraient être ajoutées plus tard, ce qui sera réduit à chaque fois que vous exécutez la requête et pourrait nuire aux performances. Cela nuit aux performances car
Quand utiliser sélectionnez *
Lorsque vous avez explicitement BESOIN de chaque colonne de la table, au lieu d'avoir besoin de chaque colonne de la table QUI EXISTE AU MOMENT QUE VOUS ÉCRIVEZ LA DEMANDE. Par exemple, si vous écriviez une application de gestion de base de données qui devait afficher l'intégralité du contenu de la table (quel qu'il soit), vous pouvez utiliser cette approche.
la source
SELECT *
serait lorsque vous effectuez des requêtes de test à l'aide du client db.Il y a quelques raisons:
Remarque: j'ai choisi INTEGER dans l'exemple ci-dessus car ils ont une taille fixe de 4 octets.
la source
Si votre application obtient des données avec SELECT * et que la structure de la table dans la base de données est modifiée (par exemple, une colonne est supprimée), votre application échouera à chaque endroit où vous référencez le champ manquant. Si vous incluez à la place toutes les colonnes dans votre requête, votre application se cassera dans le (espérons-le) un endroit où vous obtenez initialement les données, ce qui facilitera le correctif.
Cela étant dit, il existe un certain nombre de situations dans lesquelles SELECT * est souhaitable. L'une est une situation que je rencontre tout le temps, où je dois répliquer une table entière dans une autre base de données (comme SQL Server vers DB2, par exemple). Une autre est une application écrite pour afficher les tables de manière générique (c'est-à-dire sans aucune connaissance d'une table particulière).
la source
En fait, j'ai remarqué un comportement étrange lorsque j'utilisais des
select *
vues dans SQL Server 2005.Exécutez la requête suivante et vous verrez ce que je veux dire.
Comparez les résultats des 2 dernières instructions de sélection. Je crois que ce que vous verrez est le résultat de Select * référençant les colonnes par index au lieu de nom.
Si vous reconstruisez la vue, cela fonctionnera à nouveau correctement.
ÉDITER
J'ai ajouté une question distincte, * «sélectionner * à partir de la table» vs «sélectionner colA, colB, etc. à partir de la table» comportement intéressant dans SQL Server 2005 * pour examiner ce comportement plus en détail.
la source
Vous pouvez joindre deux tables et utiliser la colonne A de la deuxième table. Si vous ajoutez plus tard la colonne A à la première table (avec le même nom mais peut-être une signification différente), vous obtiendrez très probablement les valeurs de la première table et non de la seconde comme précédemment. Cela ne se produira pas si vous spécifiez explicitement les colonnes que vous souhaitez sélectionner.
Bien sûr, la spécification des colonnes provoque également parfois des bogues si vous oubliez d'ajouter les nouvelles colonnes à chaque clause de sélection. Si la nouvelle colonne n'est pas nécessaire à chaque exécution de la requête, cela peut prendre un certain temps avant que le bogue ne soit remarqué.
la source
Je comprends où vous allez en ce qui concerne l'optimisation prématurée, mais cela ne va vraiment que jusqu'à un certain point. L'intention est d'éviter une optimisation inutile au début. Vos tables sont-elles non indexées? Utiliseriez-vous nvarchar (4000) pour stocker un code postal?
Comme d'autres l'ont souligné, il existe d'autres points positifs à la spécification de chaque colonne que vous prévoyez d'utiliser dans la requête (comme la maintenabilité).
la source
Lorsque vous spécifiez des colonnes, vous vous attachez également à un ensemble spécifique de colonnes et vous vous rendez moins flexible, ce qui fait que Feuerstein se déplace, eh bien, où qu'il se trouve. Juste une pensée.
la source
SELECT * n'est pas toujours mauvais. À mon avis, du moins. Je l'utilise assez souvent pour des requêtes dynamiques renvoyant une table entière, ainsi que quelques champs calculés.
Par exemple, je veux calculer des géométries géographiques à partir d'une table "normale", c'est-à-dire une table sans aucun champ de géométrie, mais avec des champs contenant des coordonnées. J'utilise postgresql, et son extension spatiale postgis. Mais le principe s'applique dans de nombreux autres cas.
Un exemple:
une table de lieux, avec des coordonnées stockées dans des champs étiquetés x, y, z:
CREATE TABLE places (place_id integer, x numeric (10, 3), y numeric (10, 3), z numeric (10, 3), description varchar);
nourrissons-le avec quelques exemples de valeurs:
INSERT INTO places (place_id, x, y, z, description) VALUES
(1, 2.295, 48.863, 64, 'Paris, Place de l \' Étoile '),
(2, 2.945, 48.858, 40,' Paris, Tour Eiffel '),
(3, 0,373, 43,958, 90, «Condom, Cathédrale St-Pierre»);
Je veux pouvoir mapper le contenu de ce tableau, en utilisant un client SIG. La méthode normale consiste à ajouter un champ de géométrie à la table et à créer la géométrie en fonction des coordonnées. Mais je préférerais avoir une requête dynamique: de cette façon, lorsque je change de coordonnées (corrections, plus de précision, etc.), les objets mappés se déplacent réellement, dynamiquement. Voici donc la requête avec le SELECT * :
CRÉER OU REMPLACER VUE lieux_points AS
SELECT *,
GeomFromewkt ('SRID = 4326; POINT (' || x || '' || y || '' || z || ')')
FROM lieux;
Reportez-vous à postgis, pour l'utilisation de la fonction GeomFromewkt ().
Voici le résultat:
SELECT * FROM lieux_points;
La colonne la plus à droite peut désormais être utilisée par n'importe quel programme SIG pour cartographier correctement les points.
Je souhaite que la définition de la VUE puisse être conservée "telle quelle", avec le *, mais hélas ce n'est pas le cas: c'est ainsi qu'elle est stockée en interne par postgresql:
SELECT places.place_id, places.x, places.y, places.z, places.description, geomfromewkt ((((('SRID = 4326; POINT (' :: text || places.x) || '': : text) || places.y) || '' :: text) || places.z) || ')' :: text) AS geomfromewkt FROM places;
la source
Même si vous utilisez chaque colonne mais adressez le tableau de lignes par index numérique, vous aurez des problèmes si vous ajoutez une autre ligne plus tard.
C'est donc essentiellement une question de maintenabilité! Si vous n'utilisez pas le sélecteur *, vous n'aurez pas à vous soucier de vos requêtes.
la source
En sélectionnant uniquement les colonnes dont vous avez besoin, le jeu de données en mémoire est plus petit et donc votre application plus rapide.
De plus, de nombreux outils (par exemple les procédures stockées) mettent également en cache les plans d'exécution des requêtes. Si vous ajoutez ou supprimez ultérieurement une colonne (particulièrement facile si vous désactivez une vue), l'outil fera souvent une erreur lorsqu'il ne récupère pas les résultats qu'il attend.
la source
Cela rend votre code plus ambigu et plus difficile à maintenir; parce que vous ajoutez des données inutilisées supplémentaires au domaine, et que vous ne savez pas ce que vous avez voulu et lequel non. (Cela suggère également que vous pourriez ne pas savoir ou ne pas vous en soucier.)
la source
Pour répondre directement à votre question: N'utilisez pas "SELECT *" lorsque cela rend votre code plus fragile aux modifications des tables sous-jacentes. Votre code ne doit être interrompu que lorsqu'une modification est apportée à la table qui affecte directement les exigences de votre programme.
Votre application doit tirer parti de la couche d'abstraction fournie par l'accès relationnel.
la source
Je n'utilise pas SELECT * simplement parce qu'il est agréable de voir et de savoir quels champs je récupère.
la source
Généralement mauvais d'utiliser 'select *' à l'intérieur des vues car vous serez obligé de recompiler la vue en cas de changement de colonne de table. En changeant les colonnes de table sous-jacentes d'une vue, vous obtiendrez une erreur pour les colonnes inexistantes jusqu'à ce que vous reveniez et recompiliez.
la source
Ce n'est pas grave quand vous le faites
exists(select * ...)
car il n'est jamais étendu. Sinon, ce n'est vraiment utile que lorsque vous explorez des tables avec des instructions de sélection temporaires ou si vous avez défini un CTE ci-dessus et que vous voulez chaque colonne sans les taper toutes à nouveau.la source
Juste pour ajouter une chose que personne d'autre n'a mentionnée.
Select *
renvoie toutes les colonnes, quelqu'un peut ajouter une colonne plus tard que vous ne voulez pas nécessairement que les utilisateurs puissent voir, par exemple qui a mis à jour les données pour la dernière fois ou un horodatage ou des notes que seuls les gestionnaires ne devraient pas voir tous les utilisateurs, etc.En outre, lors de l'ajout d'une colonne, l'impact sur le code existant doit être examiné et pris en compte pour voir si des modifications sont nécessaires en fonction des informations stockées dans la colonne. En utilisant
select *
, cet examen sera souvent ignoré car le développeur supposera que rien ne cassera. Et en fait, rien ne peut apparaître explicitement, mais les requêtes peuvent maintenant commencer à renvoyer la mauvaise chose. Le simple fait que rien ne casse explicitement ne signifie pas que les requêtes n'auraient pas dû être modifiées.la source
car "select *" gaspillera de la mémoire lorsque vous n'avez pas besoin de tous les champs. Mais pour le serveur SQL, leurs performances sont les mêmes.
la source