Si j'ai juste besoin de 2/3 colonnes et que j'interroge SELECT *
au lieu de fournir ces colonnes dans la requête de sélection, y a-t-il une dégradation des performances concernant plus / moins d'E / S ou de mémoire?
La surcharge du réseau peut être présente si je sélectionne * sans besoin.
Mais dans une opération de sélection, le moteur de base de données extrait-il toujours le tuple atomique du disque, ou extrait-il uniquement les colonnes demandées dans l'opération de sélection?
S'il extrait toujours un tuple, la surcharge d'E / S est la même.
Dans le même temps, il peut y avoir une consommation de mémoire pour supprimer les colonnes demandées du tuple, s'il extrait un tuple.
Donc si c'est le cas, select someColumn aura plus de surcharge de mémoire que celui de select *
la source
SELECT
requêtes sont exécutées / traitées diffère d'une base de données à l'autre.CREATE VIEW foo_view AS SELECT * FROM foo;
, ajoutez des colonnes à la table foo plus tard, ces colonnes n'apparaîtront pas automatiquement dans foo_view comme prévu. En d'autres termes,*
dans ce contexte ne se développe qu'une seule fois (au moment de la création de la vue), et non par SELECT. En raison des complications découlant d'ALTER TABLE, je dirais que (en pratique)*
est considéré comme nocif.Réponses:
Il tire toujours un tuple (sauf dans les cas où le tableau a été segmenté verticalement - divisé en morceaux de colonnes), donc, pour répondre à la question que vous avez posée, cela n'a pas d'importance du point de vue des performances. Cependant, pour de nombreuses autres raisons (ci-dessous), vous devez toujours sélectionner spécifiquement les colonnes que vous souhaitez, par nom.
Il extrait toujours un tuple, car (dans le SGBDR de tous les fournisseurs avec lequel je suis familier), la structure de stockage sur disque sous-jacente pour tout (y compris les données de table) est basée sur des pages d'E / S définies (dans SQL Server par exemple, chaque page est 8 kilo-octets). Et chaque lecture ou écriture d'E / S se fait par page. Par exemple, chaque écriture ou lecture est une page complète de données.
En raison de cette contrainte structurelle sous-jacente, une conséquence est que chaque ligne de données dans une base de données doit toujours être sur une et une seule page. Il ne peut pas s'étendre sur plusieurs pages de données (sauf pour des choses spéciales comme les blobs, où les données blob réelles sont stockées dans des segments de page séparés, et la colonne de ligne de la table réelle ne reçoit alors qu'un pointeur ...). Mais ces exceptions ne sont que cela, des exceptions, et ne s'appliquent généralement pas sauf dans des cas particuliers (pour des types spéciaux de données, ou certaines optimisations pour des circonstances spéciales)
Même dans ces cas particuliers, généralement, la ligne de données du tableau elle-même (qui contient le pointeur vers les données réelles du Blob, ou autre), il doit être stocké sur une seule page IO ...
EXCEPTION. Le seul endroit où
Select *
est OK, est dans la sous-requête après une clauseExists
ouNot Exists
predicate, comme dans:EDIT: Pour répondre au commentaire de @Mike Sherer, oui c'est vrai, à la fois techniquement, avec un peu de définition pour votre cas particulier, et esthétiquement. Premièrement, même lorsque l'ensemble de colonnes demandé est un sous-ensemble de celles stockées dans un index, le processeur de requêtes doit extraire toutes les colonnes stockées dans cet index, pas seulement celles demandées, pour les mêmes raisons - TOUTES les E / S doivent être effectuées dans et les données d'index sont stockées dans les pages IO, tout comme les données de table. Donc, si vous définissez "tuple" pour une page d'index comme l'ensemble de colonnes stockées dans l'index, l'instruction est toujours vraie.
et la déclaration est vraie esthétiquement parce que le fait est qu'elle récupère les données en fonction de ce qui est stocké dans la page d'E / S, pas de ce que vous demandez, et ceci est vrai que vous accédiez à la page d'E / S de la table de base ou à un index Page E / S.
Pour d'autres raisons de ne pas utiliser
Select *
, consultez Pourquoi est-ilSELECT *
considéré comme dangereux? :la source
select *
y aura moins de surcharge de mémoire queselect column
mais la même surcharge d'E / S. donc si nous laissons la surcharge du réseau.select *
si moins de frais généraux que celui deselect column
Il y a plusieurs raisons pour lesquelles vous ne devriez jamais (jamais) utiliser
SELECT *
dans le code de production:puisque vous ne donnez aucune indication à votre base de données sur ce que vous voulez, elle devra d'abord vérifier la définition de la table afin de déterminer les colonnes de cette table. Cette recherche coûtera du temps - pas beaucoup en une seule requête - mais elle s'additionne avec le temps
si vous n'avez besoin que de 2/3 des colonnes, vous sélectionnez 1/3 de trop de données qui doivent être extraites du disque et envoyées sur le réseau
si vous commencez à vous fier à certains aspects des données, par exemple l'ordre des colonnes renvoyées, vous pourriez avoir une mauvaise surprise une fois que la table est réorganisée et que de nouvelles colonnes sont ajoutées (ou les colonnes existantes supprimées)
dans SQL Server (pas sûr des autres bases de données), si vous avez besoin d'un sous-ensemble de colonnes, il y a toujours une chance qu'un index non clusterisé couvre cette demande (contient toutes les colonnes nécessaires). Avec a
SELECT *
, vous renoncez à cette possibilité dès le départ. Dans ce cas particulier, les données seraient récupérées à partir des pages d'index (si celles-ci contiennent toutes les colonnes nécessaires) et donc les E / S disque et la surcharge de mémoire seraient beaucoup moins importantes par rapport à uneSELECT *....
requête.Oui, cela prend un peu plus de frappe au départ (des outils comme SQL Prompt pour SQL Server vous aideront même là-bas) - mais c'est vraiment un cas où il y a une règle sans aucune exception: n'utilisez jamais SELECT * dans votre code de production. DÉJÀ.
la source
Where Exists (Select * From ...
) l'utilisation deSelect *
n'est certainement pas un problème, et dans certains cercles est considérée comme une meilleure pratique.IF EXISTS(SELECT *...
c'est un cas particulier - puisque là, aucune donnée n'est vraiment récupérée, mais c'est juste un contrôle d'existence, le SELECT * n'est pas un problème là-bas ...Tu devrais toujours seulement
select
utiliser les colonnes dont vous avez réellement besoin. Il n'est jamais moins efficace de sélectionner moins au lieu de plus, et vous rencontrez également moins d'effets secondaires inattendus - comme accéder à vos colonnes de résultats côté client par index, puis rendre ces index incorrects en ajoutant une nouvelle colonne à la table.[modifier]: signifiait accès. Le cerveau stupide se réveille toujours.
la source
SELECT *
avec lui.Sauf si vous stockez de gros blobs, les performances ne sont pas un problème. La principale raison de ne pas utiliser SELECT * est que si vous utilisez des lignes retournées comme tuples, les colonnes reviennent dans l'ordre que le schéma spécifie, et si cela change, vous devrez corriger tout votre code.
D'un autre côté, si vous utilisez un accès de style dictionnaire, l'ordre dans lequel les colonnes reviennent n'a pas d'importance car vous y accédez toujours par nom.
la source
Cela me fait immédiatement penser à une table que j'utilisais et qui contenait une colonne de type
blob
; il contenait généralement une image JPEG, de quelquesMb
s.Inutile de dire que je ne l' ai pas
SELECT
cette colonne à moins que je vraiment besoin. Avoir ces données flottantes - en particulier lorsque j'ai sélectionné plusieurs lignes - n'était qu'un problème.Cependant, j'admets que je recherche généralement toutes les colonnes d'une table.
la source
Lors d'une sélection SQL, la base de données va toujours se référer aux métadonnées de la table, qu'il s'agisse de SELECT * pour SELECT a, b, c ... Pourquoi? Parce que c'est là que se trouvent les informations sur la structure et la disposition de la table sur le système.
Il doit lire ces informations pour deux raisons. Un, pour simplement compiler la déclaration. Il doit s'assurer que vous spécifiez au moins une table existante. En outre, la structure de la base de données peut avoir changé depuis la dernière exécution d'une instruction.
Maintenant, évidemment, les métadonnées DB sont mises en cache dans le système, mais c'est encore un traitement qui doit être effectué.
Ensuite, les métadonnées sont utilisées pour générer le plan de requête. Cela se produit également à chaque fois qu'une instruction est compilée. Encore une fois, cela fonctionne avec les métadonnées mises en cache, mais c'est toujours fait.
Le seul moment où ce traitement n'est pas effectué est lorsque la base de données utilise une requête précompilée ou a mis en cache une requête précédente. C'est l'argument pour utiliser des paramètres de liaison plutôt que du SQL littéral. "SELECT * FROM TABLE WHERE key = 1" est une requête différente de "SELECT * FROM TABLE WHERE key =?" et le "1" est lié à l'appel.
Les bases de données reposent fortement sur la mise en cache des pages pour leur travail. De nombreuses bases de données modernes sont suffisamment petites pour tenir complètement en mémoire (ou, peut-être devrais-je dire, la mémoire moderne est suffisamment grande pour contenir de nombreuses bases de données). Ensuite, votre principal coût d'E / S sur le back-end est la journalisation et les vidages de page.
Cependant, si vous utilisez toujours le disque de votre base de données, une optimisation principale effectuée par de nombreux systèmes consiste à s'appuyer sur les données des index, plutôt que sur les tables elles-mêmes.
Si tu as:
Ensuite, si vous faites "SELECT id, nom FROM customer WHERE id = 1", il est très probable que votre DB extraira ces données de l'index, plutôt que des tables.
Pourquoi? Il utilisera probablement l'index de toute façon pour satisfaire la requête (par rapport à une analyse de table), et même si 'nom' n'est pas utilisé dans la clause where, cet index sera toujours la meilleure option pour la requête.
Maintenant, la base de données a toutes les données dont elle a besoin pour satisfaire la requête, il n'y a donc aucune raison de consulter les pages de la table elles-mêmes. L'utilisation de l'index entraîne moins de trafic disque car vous avez une densité de lignes plus élevée dans l'index que dans la table en général.
Ceci est une explication ondulée à la main d'une technique d'optimisation spécifique utilisée par certaines bases de données. Beaucoup ont plusieurs techniques d'optimisation et de réglage.
Au final, SELECT * est utile pour les requêtes dynamiques que vous devez taper à la main, je ne l'utiliserais jamais pour du "vrai code". L'identification de colonnes individuelles donne à la base de données plus d'informations qu'elle peut utiliser pour optimiser la requête, et vous donne un meilleur contrôle de votre code contre les changements de schéma, etc.
la source
Je pense qu'il n'y a pas de réponse exacte à votre question, car vous vous interrogez sur les performances et la facilité de maintenance de vos applications.
Select column
est plus performanteselect *
, mais si vous développez un système d'objet orienté, vous aimerez l'utiliserobject.properties
et vous pourrez avoir besoin de propriétés dans n'importe quelle partie des applications, alors vous devrez écrire plus de méthodes pour obtenir des propriétés dans des situations spéciales si vous ne le faites pas utiliserselect *
et remplir toutes les propriétés. Vos applications doivent avoir de bonnes performances en utilisantselect *
et dans certains cas, vous devrez utiliser la colonne de sélection pour améliorer les performances. Ensuite, vous aurez le meilleur de deux mondes, la possibilité d'écrire et de maintenir des applications et des performances lorsque vous avez besoin de performances.la source
La réponse acceptée ici est fausse. Je suis tombé sur cela lorsqu'une autre question a été fermée comme une copie de celle-ci (alors que j'écrivais encore ma réponse - grr - d'où le SQL ci-dessous fait référence à l'autre question).
Vous devez toujours utiliser l'attribut SELECT, l'attribut .... NOT SELECT *
C'est principalement pour les problèmes de performances.
N'est pas un exemple très utile. Considérez plutôt:
S'il y a un index sur (nom, téléphone), la requête peut être résolue sans avoir à rechercher les valeurs pertinentes dans la table - il y a un index de couverture .
De plus, supposons que la table ait un BLOB contenant une image de l'utilisateur, et un CV téléchargé, et une feuille de calcul ... en utilisant SELECT * ramènera toutes ces informations dans les tampons du SGBD (forçant à sortir d'autres informations utiles du cache). Ensuite, tout sera envoyé au client en utilisant le temps disponible sur le réseau et la mémoire sur le client pour les données qui sont redondantes.
Cela peut également causer des problèmes fonctionnels si le client récupère les données sous forme de tableau énuméré (tel que mysql_fetch_array de PHP ($ x, MYSQL_NUM)). Peut-être que lorsque le code a été écrit, «téléphone» était la troisième colonne à être retournée par SELECT *, mais alors quelqu'un arrive et décide d'ajouter une adresse e-mail à la table, placée avant «téléphone». Le champ souhaité est maintenant déplacé vers la 4ème colonne.
la source
Il y a des raisons de faire les choses de toute façon. J'utilise beaucoup SELECT * sur PostgreSQL car il y a beaucoup de choses que vous pouvez faire avec SELECT * dans PostgreSQL que vous ne pouvez pas faire avec une liste de colonnes explicite, en particulier dans les procédures stockées. De même dans Informix, SELECT * sur une arborescence de table héritée peut vous donner des lignes irrégulières alors qu'une liste de colonnes explicite ne le peut pas car des colonnes supplémentaires dans les tables enfants sont également renvoyées.
La principale raison pour laquelle je fais cela dans PostgreSQL est que cela garantit que j'obtiens un type bien formé spécifique à une table. Cela me permet de prendre les résultats et de les utiliser comme type de table dans PostgreSQL. Cela permet également d'avoir beaucoup plus d'options dans la requête qu'une liste de colonnes rigides.
D'autre part, une liste de colonnes rigide vous permet de vérifier au niveau de l'application que les schémas de base de données n'ont pas changé de certaines manières et cela peut être utile. (Je fais de telles vérifications à un autre niveau.)
En ce qui concerne les performances, j'ai tendance à utiliser des VIEWs et des procédures stockées renvoyant des types (puis une liste de colonnes à l'intérieur de la procédure stockée). Cela me donne le contrôle sur les types renvoyés.
Mais gardez à l'esprit que j'utilise SELECT * généralement sur une couche d'abstraction plutôt que sur des tables de base.
la source
Référence tirée de cet article:
Sans SELECT *: lorsque vous utilisez «SELECT *» à ce moment-là, vous sélectionnez plus de colonnes dans la base de données et une partie de cette colonne peut ne pas être utilisée par votre application. Cela créera des coûts et une charge supplémentaires sur le système de base de données et plus de données circuleront sur le réseau.
Avec SELECT *: Si vous avez des exigences particulières et que vous avez créé un environnement dynamique lors de l'ajout ou de la suppression de colonne automatiquement géré par le code de l'application. Dans ce cas particulier, vous n'avez pas besoin de changer le code de l'application et de la base de données et cela affectera automatiquement l'environnement de production. Dans ce cas, vous pouvez utiliser «SELECT *».
la source
Juste pour ajouter une nuance à la discussion que je ne vois pas ici: en termes d'E / S, si vous utilisez une base de données avec un stockage orienté colonnes, vous pouvez faire BEAUCOUP moins d'E / S si vous ne demandez que certaines Colonnes. Au fur et à mesure que nous passons aux SSD, les avantages peuvent être un peu plus petits par rapport au stockage orienté lignes, mais il n'y a a) que la lecture des blocs contenant des colonnes qui vous intéressent b) la compression, qui réduit généralement considérablement la taille des données sur le disque et donc la volume de données lues à partir du disque.
Si vous n'êtes pas familier avec le stockage orienté colonnes, une implémentation pour Postgres provient de Citus Data, une autre est Greenplum, un autre Paraccel, une autre (en gros) est Amazon Redshift. Pour MySQL, il y a Infobright, InfiniDB maintenant presque disparu. D'autres offres commerciales incluent Vertica de HP, Sybase IQ, Teradata ...
la source
égal
la source