Pourquoi est-ce une SELECT *
mauvaise pratique? Cela ne signifierait-il pas moins de code à modifier si vous ajoutiez une nouvelle colonne que vous vouliez?
Je comprends que SELECT COUNT(*)
c'est un problème de performances sur certaines bases de données, mais que faire si vous vouliez vraiment chaque colonne?
SELECT COUNT(*)
être mauvais est incroyablement vieux et obsolète . Pour plus d'informations surSELECT *
- voir: stackoverflow.com/questions/1960036/…SELECT COUNT(*)
donne une réponse différente deSELECT COUNT(SomeColumn)
sauf si la colonne est une colonne NOT NULL. Et l'optimiseur peut donnerSELECT COUNT(*)
un traitement spécial - et le fait généralement. Notez également que leWHERE EXISTS(SELECT * FROM SomeTable WHERE ...)
traitement des cas spéciaux est donné.Réponses:
Il y a vraiment trois raisons principales:
Inefficacité dans la transmission des données au consommateur. Lorsque vous sélectionnez *, vous récupérez souvent plus de colonnes de la base de données que votre application n'en a vraiment besoin pour fonctionner. Cela entraîne le déplacement de plus de données du serveur de base de données vers le client, ce qui ralentit l'accès et augmente la charge sur vos machines, tout en prenant plus de temps pour parcourir le réseau. Cela est particulièrement vrai lorsque quelqu'un ajoute de nouvelles colonnes à des tables sous-jacentes qui n'existaient pas et n'étaient pas nécessaires lorsque les consommateurs d'origine codaient leur accès aux données.
Problèmes d'indexation. Envisagez un scénario dans lequel vous souhaitez régler une requête à un niveau élevé de performances. Si vous deviez utiliser * et qu'il renvoyait plus de colonnes que vous n'en aviez réellement besoin, le serveur devrait 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 seriez pas en mesure de créer un index qui couvrirait simplement les colonnes de votre liste SELECT, et même si vous l'avez fait (y compris toutes les colonnes [ frisson ]), le gars suivant qui est venu et a ajouté une colonne au sous-jacent La table entraînerait l'optimiseur à ignorer votre index de couverture optimisé, et vous constateriez probablement que les performances de votre requête chuteraient considérablement sans raison apparente.
Problèmes contraignants. Lorsque vous sélectionnez *, il est possible de récupérer deux colonnes du même nom à partir de deux tables différentes. Cela peut souvent planter votre consommateur de données. Imaginez une requête qui joint deux tables, qui contiennent toutes deux une colonne appelée "ID". Comment un consommateur saurait-il lequel était lequel? SELECT * peut également confondre les vues (au moins dans certaines versions de SQL Server) lorsque les structures de table 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 gars qui viendra pourrait n'avoir aucun moyen de savoir qu'il doit s'inquiéter d'ajouter une colonne qui entrera en collision avec votre déjà développé des noms.
Mais tout n'est pas mauvais pour SELECT *. Je l'utilise généreusement pour ces cas d'utilisation:
Requêtes ad hoc. Lorsque vous essayez de déboguer quelque chose, en particulier sur une table étroite avec laquelle je ne suis peut-être pas familier, SELECT * est souvent mon meilleur ami. Cela m'aide à voir ce qui se passe sans avoir à faire de nombreuses recherches sur les noms des colonnes sous-jacentes. Cela devient un «plus» plus grand plus les noms de colonne sont longs.
Lorsque * signifie "une rangée". Dans les cas d'utilisation suivants, SELECT * est très bien, et les rumeurs selon lesquelles c'est un tueur de performances ne sont que des légendes urbaines qui pouvaient avoir une certaine validité il y a de nombreuses années, mais pas maintenant:
dans ce cas, * signifie "compter les lignes". Si vous deviez utiliser un nom de colonne au lieu de *, il compterait les lignes où la valeur de cette colonne n'était pas nulle . COUNT (*), pour moi, fait vraiment ressortir le concept selon lequel vous comptez les lignes , et vous évitez les cas de bord étranges causés par les NULLs éliminés de vos agrégats.
Il en va de même avec ce type de requête:
dans toute base de données digne de ce nom, * signifie simplement "une ligne". Peu importe ce que vous mettez dans la sous-requête. Certaines personnes utilisent l'ID de b dans la liste SELECT, ou elles utiliseront le numéro 1, mais l'OMI ces conventions sont à peu près absurdes. Ce que vous voulez dire, c'est "compter la rangée", 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 sais seulement que cela est vrai avec SQL Server et Oracle.)
la source
*
est que dans certaines situations, il peut mieux tirer parti des systèmes de cache de MySQL. Si vous utilisez un grand nombre de semblablesselect
requêtes qui demandent différents noms de colonnes (select A where X
,select B where X
, ...) en utilisant unselect * where X
permettra au cache de traiter un plus grand nombre de requêtes qui peut entraîner une augmentation substantielle des performances. Il s'agit d'un scénario spécifique à l'application, mais il convient de le garder à l'esprit.SELECT *
force les développeurs à examiner le ou les schémas de table impliqués, afin de déterminer les colonnes affectées / disponibles, comme dans unforeach
ouserialize
. La tâche de regarder à plusieurs reprises les schémas pour suivre ce qui se passe augmentera inévitablement le temps total impliqué à la fois dans le débogage et le développement de code associé.Le caractère astérisque, "*", dans l'instruction SELECT est un raccourci pour toutes les colonnes des tables impliquées dans la requête.
Performance
La
*
sténographie peut être plus lente car:SELECT *
par câble risque une analyse complète du tableauEntretien
Lors de l'utilisation
SELECT *
:SELECT *
masquera une erreur en attente de se produire si l'ordre d'une colonne a été modifié.Conception
SELECT *
est un anti-motif :Quand faut-il utiliser "SELECT *"?
Il est acceptable de l'utiliser
SELECT *
lorsqu'il existe un besoin explicite pour chaque colonne des tables impliquées, par opposition à chaque colonne qui existait lorsque la requête a été écrite. La base de données étendra en interne le * dans la liste complète des colonnes - il n'y a pas de différence de performances.Sinon, répertoriez explicitement toutes les colonnes à utiliser dans la requête, de préférence lorsque vous utilisez un alias de table.
la source
Même si vous souhaitez sélectionner chaque colonne maintenant, vous ne voudrez peut-être pas sélectionner chaque colonne après que quelqu'un a ajouté une ou plusieurs nouvelles colonnes. Si vous écrivez la requête avec
SELECT *
vous, vous risquez à un moment donné que quelqu'un ajoute une colonne de texte, ce qui ralentit l'exécution de votre requête, même si vous n'avez pas réellement besoin de cette colonne.Les chances sont que si vous voulez réellement utiliser la nouvelle colonne, vous devrez de toute façon apporter beaucoup d'autres modifications à votre code. Vous ne faites qu'économiser
, new_column
- juste quelques caractères de frappe.la source
*
peut changer de façon inattendue et cela peut faire des ravages dans l'application elle-même: les colonnes référencées par ordinal (par exemple sqldatareader.getstring (2)) récupèrent soudainement une colonne différente , toutINSERT ... SELECT *
se cassera et ainsi de suite et ainsi de suite.SELECT *
ne s'agit pas non plus de sauvegarder quelques caractères. Il s'agit de gagner des heures de débogage car il est facile d'oublier de spécifier de nouvelles colonnes ajoutées.Si vous nommez les colonnes dans une instruction SELECT, elles seront renvoyées dans l'ordre spécifié et peuvent ainsi être référencées en toute sécurité par un index numérique. Si vous utilisez "SELECT *", vous pouvez finir par recevoir les colonnes dans une séquence arbitraire et ne pouvez donc utiliser les colonnes que par leur nom en toute sécurité. À moins que vous ne sachiez à l'avance ce que vous voudrez faire avec une nouvelle colonne ajoutée à la base de données, l'action correcte la plus probable est de l'ignorer. Si vous allez ignorer de nouvelles colonnes ajoutées à la base de données, il n'y a aucun avantage à les récupérer.
la source
select *
puis utiliser les colonnes par index serait horrible, mais utiliserselect X, Y, Z
ouselect A,B,C
puis passer le lecteur de données résultant au code qui s'attend à faire quelque chose avec les données des colonnes 0, 1 et 2 semble une manière parfaitement raisonnable de permettre au même code d'agir sur X, Y, Z ou A, B, C. Notez 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.Dans de nombreuses situations, SELECT * provoquera des erreurs au moment de l'exécution dans votre application, plutôt qu'au moment de la conception. Il masque la connaissance des changements de colonne ou des mauvaises références dans vos applications.
la source
Si vous voulez vraiment chaque colonne, je n'ai pas vu de différence de performance entre select (*) et nommer les colonnes. Le pilote pour nommer les colonnes peut être simplement d'être explicite sur les colonnes que vous attendez de voir dans votre code.
Souvent, cependant, vous ne voulez pas que chaque colonne et la sélection (*) peuvent entraîner un travail inutile pour le serveur de base de données et des informations inutiles devant être transmises sur le réseau. Il est peu probable que cela cause un problème notable à moins que le système ne soit fortement utilisé ou que la connectivité réseau soit lente.
la source
Considérez-le comme réduisant le couplage entre l'application et la base de données.
Pour résumer l'aspect «odeur de code»:
SELECT *
crée une dépendance dynamique entre l'application et le schéma. Restreindre son utilisation est un moyen de rendre la dépendance plus définie, sinon une modification de la base de données risque davantage de faire planter votre application.la source
Si vous ajoutez des champs à la table, ils seront automatiquement inclus dans toutes vos requêtes où vous les utilisez
select *
. Cela peut sembler pratique, mais cela rendra votre application plus lente car vous récupérez plus de données que vous n'en avez besoin, et cela bloquera votre application à un moment donné.Il y a une limite pour la quantité de données que vous pouvez récupérer dans chaque ligne d'un résultat. Si vous ajoutez des champs à vos tables afin qu'un résultat finisse par dépasser cette limite, vous obtenez un message d'erreur lorsque vous essayez d'exécuter la requête.
C'est le genre d'erreurs difficiles à trouver. Vous effectuez un changement à un endroit et il explose à un autre endroit qui n'utilise pas du tout les nouvelles données. Il peut même s'agir d'une requête moins fréquemment utilisée, de sorte qu'il faut un certain temps avant que quelqu'un l'utilise, ce qui rend encore plus difficile la connexion de l'erreur au changement.
Si vous spécifiez les champs que vous souhaitez dans le résultat, vous êtes à l'abri de ce type de dépassement de surcharge.
la source
Référence tirée de cet article.
N'allez jamais avec "SELECT *",
Je n'ai trouvé qu'une seule raison d'utiliser "SELECT *"
Si vous avez des exigences particulières et créé un environnement dynamique lors de l'ajout ou de la suppression d'une colonne, gérer automatiquement par le code d'application. Dans ce cas particulier, vous n'avez pas besoin de modifier le code de l'application et de la base de données, ce qui affectera automatiquement l'environnement de production. Dans ce cas, vous pouvez utiliser «SELECT *».
la source
En règle générale, vous devez adapter les résultats de votre
SELECT * ...
dans des structures de données de différents types. Sans spécifier dans quel ordre les résultats arrivent, il peut être difficile de tout aligner correctement (et les champs plus obscurs sont beaucoup plus faciles à manquer).De cette façon, vous pouvez ajouter des champs à vos tables (même au milieu) pour diverses raisons sans casser le code d'accès sql dans toute l'application.
la source
L'utilisation
SELECT *
lorsque vous n'avez besoin que de quelques colonnes signifie beaucoup plus de données transférées que vous n'en avez besoin. Cela ajoute du traitement sur la base de données et augmente la latence lors de la transmission des données au client. Ajoutez à cela qu'il utilisera plus de mémoire lors du chargement, dans certains cas beaucoup plus, comme les gros fichiers BLOB, c'est principalement une question d'efficacité.En plus de cela, cependant, il est plus facile de voir en regardant la requête quelles colonnes sont chargées, sans avoir à rechercher ce qui est dans la table.
Oui, si vous ajoutez une colonne supplémentaire, ce serait plus rapide, mais dans la plupart des cas, vous voudrez / devrez modifier votre code à l'aide de la requête pour accepter les nouvelles colonnes de toute façon, et il est possible que vous obteniez celles que vous ne faites pas '' t vouloir / attendre peut causer des problèmes. Par exemple, si vous saisissez toutes les colonnes, puis comptez sur l'ordre dans une boucle pour attribuer des variables, puis en ajouter une, ou si les ordres des colonnes changent (vu que cela se produit lors de la restauration à partir d'une sauvegarde), cela peut tout jeter.
C'est également le même type de raisonnement pour lequel si vous faites un,
INSERT
vous devez toujours spécifier les colonnes.la source
Je ne pense pas qu'il puisse vraiment y avoir une règle générale pour cela. Dans de nombreux cas, j'ai évité SELECT *, mais j'ai également travaillé avec des cadres de données où SELECT * était très bénéfique.
Comme pour tout, il y a des avantages et des coûts. Je pense qu'une partie de l'équation avantages / coûts est simplement le contrôle que vous avez sur les infrastructures de données. Dans les cas où le SELECT * fonctionnait bien, les structures de données étaient étroitement contrôlées (il s'agissait de logiciels de vente au détail), il n'y avait donc pas beaucoup de risques que quelqu'un se faufile dans un immense champ BLOB dans une table.
la source
La sélection avec le nom de colonne augmente la probabilité que le moteur de base de données puisse accéder aux données à partir des index plutôt que d'interroger les données de la table.
SELECT * expose votre système à des changements de performances et de fonctionnalités inattendus dans le cas où votre schéma de base de données change parce que vous allez ajouter de nouvelles colonnes à la table, même si votre code n'est pas prêt à utiliser ou à présenter ces nouvelles données.
la source
Il y a aussi une raison plus pragmatique: l'argent. Lorsque vous utilisez une base de données cloud et que vous devez payer pour les données traitées, il n'y a aucune explication pour lire les données que vous rejeterez immédiatement.
Par exemple: BigQuery :
et Contrôlez la projection - Évitez SELECT * :
la source
Comprenez vos besoins avant de concevoir le schéma (si possible).
En savoir plus sur les données, 1) l'indexation 2) le type de stockage utilisé, 3) le moteur ou les fonctionnalités du fournisseur; c'est-à-dire ... mise en cache, capacités en mémoire 4) types de données 5) taille de la table 6) fréquence de la requête 7) charges de travail associées si la ressource est partagée 8) Test
A) Les exigences varieront. Si le matériel ne peut pas prendre en charge la charge de travail attendue, vous devez réévaluer comment fournir les exigences dans la charge de travail. Concernant la colonne d'addition au tableau. Si la base de données prend en charge les vues, vous pouvez créer une vue indexée (?) Des données spécifiques avec les colonnes nommées spécifiques (vs sélectionner '*'). Passez régulièrement en revue vos données et votre schéma pour vous assurer de ne jamais tomber dans le syndrome "Garbage-in" -> "Garbage-out".
En supposant qu'il n'y a pas d'autre solution; vous pouvez prendre en compte les éléments suivants. Il existe toujours plusieurs solutions à un problème.
1) Indexation: La sélection * exécutera un scan de table. En fonction de divers facteurs, cela peut impliquer une recherche de disque et / ou un conflit avec d'autres requêtes. Si la table est polyvalente, assurez-vous que toutes les requêtes sont performantes et exécutez-les au-dessous de votre heure cible. S'il y a une grande quantité de données et que votre réseau ou autre ressource n'est pas réglé; vous devez en tenir compte. La base de données est un environnement partagé.
2) type de stockage. C'est-à-dire: si vous utilisez des SSD, un disque ou une mémoire. Les temps d'E / S et la charge sur le système / processeur varient.
3) Le DBA peut-il régler la base de données / tables pour des performances plus élevées? En supposant que pour quelque raison que ce soit, les équipes ont décidé que la sélection «*» est la meilleure solution au problème; la base de données ou la table peut-elle être chargée en mémoire. (Ou une autre méthode ... peut-être que la réponse a été conçue pour répondre avec un délai de 2 à 3 secondes? --- pendant qu'une publicité est diffusée pour gagner les revenus de l'entreprise ...)
4) Commencez par la ligne de base. Comprenez vos types de données et comment les résultats seront présentés. Types de données plus petits, le nombre de champs réduit la quantité de données renvoyées dans l'ensemble de résultats. Cela laisse des ressources disponibles pour d'autres besoins du système. Les ressources système ont généralement une limite; «toujours» travailler en dessous de ces limites pour assurer la stabilité et un comportement prévisible.
5) taille de la table / des données. sélectionner «*» est courant avec les petites tables. Ils tiennent généralement en mémoire et les temps de réponse sont rapides. Encore une fois ... revoyez vos besoins. Planifier le fluage des fonctionnalités; planifiez toujours les besoins actuels et futurs.
6) Fréquence des requêtes / requêtes. Soyez conscient des autres charges de travail sur le système. Si cette requête se déclenche toutes les secondes et que la table est minuscule. L'ensemble de résultats peut être conçu pour rester dans le cache / la mémoire. Cependant, si la requête est un processus par lots fréquent avec des gigaoctets / téraoctets de données ... il est préférable de consacrer des ressources supplémentaires pour éviter que d'autres charges de travail ne soient affectées.
7) Charges de travail connexes. Comprenez comment les ressources sont utilisées. Le réseau / système / base de données / table / application est-il dédié ou partagé? Quelles sont les parties prenantes? Est-ce pour la production, le développement ou l'AQ? Est-ce une "solution miracle" temporaire? Avez-vous testé le scénario? Vous serez surpris du nombre de problèmes pouvant exister sur le matériel actuel aujourd'hui. (Oui, les performances sont rapides ... mais la conception / les performances sont toujours dégradées.) Le système doit-il effectuer 10 000 requêtes par seconde contre 5 à 10 requêtes par seconde? Le serveur de base de données est-il dédié ou exécute-t-il d'autres applications de surveillance sur la ressource partagée? Certaines applications / langues; Les O / S consommeront 100% de la mémoire, provoquant divers symptômes / problèmes.
8) Test: testez vos théories et comprenez autant que possible. Votre problème de sélection «*» peut être un gros problème, ou il peut être quelque chose dont vous n'avez même pas besoin de vous inquiéter.
la source