136 votes

sélectionnez * vs sélectionnez la colonne

si j'ai juste besoin de 2/3 des colonnes et j'ai une requête SELECT * au lieu de fournir ces colonnes dans une requête select. est-il de toute dégradation des performances en ce qui concerne plus/moins d'e/S ou de mémoire ??

la surcharge du réseau peut être présent si je ne sélectionnez * sans nécessité.

Mais dans une opération de sélection le moteur de base de données tire toujours atomique tuple à partir du disque ? ou il tire uniquement les colonnes demandées dans l'opération de sélection.

Si il tire toujours un tuple puis-je/O surcharge est la même.

dans le même temps. il y a peut être une consommation de mémoire pour enlever les colonnes demandées pour un n-uplet. si elle tire un n-uplet.

Donc, si c'est le cas, sélectionnez someColumn aura plus de surcharge de mémoire que de sélectionner

121voto

marc_s Points 321990

Il y a plusieurs raisons pour lesquelles vous ne devriez jamais (jamais jamais) utiliser SELECT * de la production de code:

  • puisque vous ne donnez pas votre base de données toutes les indications sur ce que vous voulez, il faudra d'abord vérifier le tableau de définition afin de déterminer les colonnes de cette table. Cette recherche va coûter un peu de temps - pas beaucoup en une seule requête, mais il ajoute au fil du temps

  • si vous avez besoin seulement les 2/3 des colonnes, vous êtes en sélectionnant 1/3 de trop de données qui doit être de la récupération à partir de disques et de les envoyer sur le réseau

  • si vous commencez à appuyer sur certains aspects de les données, par exemple, l'ordre des colonnes retournées, vous pourriez avoir une mauvaise surprise une fois que la table est réorganisé et nouvelles colonnes sont ajoutées (ou existants supprimé)

  • dans SQL Server (pas sûr sur d'autres bases de données), si vous avez besoin d'un sous-ensemble de colonnes, il y a toujours une chance un index non-cluster peut être couvrant la demande contient toutes les colonnes nécessaires). Avec un SELECT *, vous êtes renoncer à cette possibilité en droit de l'obtenir-aller. Dans ce cas particulier, les données sont récupérées à partir de la page d'index (si ceux-ci contiennent toutes les colonnes) et donc I/O disque et de la mémoire généraux serait beaucoup moins par rapport à faire un SELECT *.... de la requête.

Oui, il faut un peu plus de taper dans un premier temps (des outils comme Invite SQL pour SQL Server va même vous aider, il ya) - mais c'est vraiment un cas où il y a une règle sans exception: ne jamais utiliser SELECT * dans votre code de production. JAMAIS.

34voto

Charles Bretana Points 59899

Il tire toujours un n-uplet (sauf dans les cas où le tableau a été verticalement segmenté - divisé en colonnes pièces), donc pour répondre à la question que vous avez posée, il n'a pas d'importance d'un point de vue performance. Toutefois, pour de nombreuses autres raisons, vous devez toujours sélectionner spécifiquement les colonnes que vous voulez, par nom.

Il tire toujours un tuple, parce que, dans tous les vendeurs de SGBDR, je suis familier avec, sous-jacent de stockage sur disque de la structure pour tout (y compris les données de la table) est la fonction définie sur I/O Pages (dans SQL Server, par exemple, chaque Page est de 8 kilo-octets. Et tous les I/O de lecture ou d'écriture est en Page.. I. e., chaque écriture ou de la lecture est une Page complète de données.

En raison de cette contrainte structurelle, 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 certaines choses comme les gouttes, où le blob données sont stockées dans une Page séparée-morceaux, et de la ligne de la table de la colonne puis obtient seulement un pointeur...). Mais ces exceptions ne sont que des exceptions, et en général ne s'applique pas, sauf dans des cas particuliers ( pour certains types de données, ou de certaines optimisations pour des circonstances spéciales)
Même dans ces cas particuliers, en général, la ligne de la table de données elle-même (qui contient le pointeur vers les données réelles pour la Goutte, ou quoi que ce soit), il doit être stocké sur un seul IO Page...

EXCEPTON. Le seul endroit où l' Select * est ok, dans la sous-requête après un Exists ou Not Exists prédicat de la clause, comme dans:

   Select colA, colB
   From table1 t1
   Where Exists (Select * From Table2
                 Where column = t1.colA)

EDIT: Pour l'adresse @Mike Sherer commentaire, Oui c'est vrai, à la fois techniquement, avec un peu de définition pour votre cas particulier, et esthétiquement. Tout d'abord, même lorsque l'ensemble des colonnes demandées sont un sous-ensemble de ceux qui sont stockés dans certains index, le processeur de requête doit aller chercher chaque colonne stockées dans l'indice, et pas seulement ceux demandés, pour les mêmes raisons - TOUTES les I/O doit être fait dans les pages, et les données d'index est stocké dans IO Pages tout comme les données de la table. Donc, si vous définissez "tuple" pour une page d'index comme l'ensemble des colonnes stockées dans l'index, l'instruction est toujours vrai.
et l'énoncé est vrai esthétiquement, parce que le point est qu'il récupère des données basées sur ce qui est stocké dans le I/O de la page, pas sur ce que vous demandez, et ce vrai si vous êtes accédant à la base de la table I/O Page ou d'un indice I/O Page.

22voto

Donnie Points 17312

Vous ne devriez toujours utiliser que select des 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.

[edit]: Ce qui signifie accéder. Stupide cerveau encore en train de se réveiller.

6voto

Richard JP Le Guen Points 13306

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 quelques Mb s.

Inutile de dire que je n'ai pas SELECT cette colonne à moins d'en avoir vraiment besoin. Avoir ces données en suspens - particulièrement lorsque j'ai sélectionné plusieurs lignes - était un problème.

Cependant, j'admettrai que, normalement, je demande toutes les colonnes d'une table.

6voto

Will Hartung Points 57465

Lors d'un select SQL, la DB est toujours de consulter les métadonnées de la table, qu'il s'agisse d'SÉLECTIONNEZ * pour SÉLECTIONNER a, b, c... Pourquoi? Parce que c'est là que l'information sur la structure et l'agencement de la table sur le système.

Il y a qu'à lire cette information pour deux raisons. L'un, tout simplement de compiler la déclaration. Il doit assurez-vous de spécifier une table existante, à tout le moins. Aussi, la structure de base de données peuvent avoir changé depuis la dernière fois qu'une instruction a été exécutée.

Maintenant, évidemment, DB métadonnées sont mises en cache dans le système, mais il est toujours en cours de traitement qui doit être fait.

Ensuite, les métadonnées sont utilisées pour générer le plan de requête. Cela se produit chaque fois qu'une instruction est compilé en tant que bien. Encore une fois, cela va à l'encontre de mise en cache de métadonnées, mais c'est toujours fait.

Le seul moment où ce traitement n'est pas fait, c'est quand la bd est à l'aide d'un pré-compilés de la requête, ou a mis en cache une requête précédente. C'est l'argument pour l'utilisation de paramètres de liaison plutôt que de SQL littérale. "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.

DBs s'appuient fortement sur la page mise en cache pour y travailler. De nombreuses modernes DBs sont suffisamment petits pour tenir entièrement dans la mémoire (ou, devrais-je dire, de mémoire moderne est assez grand pour s'adapter à de nombreux DBs). Alors votre principal coût d'e/S sur le back-end est de la journalisation et de la page de bouffées de chaleur.

Toutefois, si vous êtes toujours frapper le disque pour votre DB, l'un primaire, l'optimisation effectuée par de nombreux systèmes est de s'appuyer sur les données dans les index, plutôt que de les tables elles-mêmes.

Si vous avez:

CREATE TABLE customer (
    id INTEGER NOT NULL PRIMARY KEY,
    name VARCHAR(150) NOT NULL,
    city VARCHAR(30),
    state VARCHAR(30),
    zip VARCHAR(10));

CREATE INDEX k1_customer ON customer(id, name);

Ensuite, si vous faites "SELECT id, nom from client where id = 1", il est très probable que vous DB va tirer de ces données à partir de l'index, plutôt que de les tables.

Pourquoi? Il faudra probablement utiliser l'index pour satisfaire à la requête (vs une analyse de la table), et même si le " nom " n'est pas utilisée dans la clause where, cet indice sera toujours la meilleure option pour la requête.

Maintenant, la base de données dispose de toutes les données dont il a besoin pour satisfaire à la requête, donc il n'y a pas de raison de frapper la table des pages elles-mêmes. En utilisant les résultats de l'indice en moins de trafic sur le disque puisque vous avez une plus grande densité de lignes dans l'index vs la table en général.

C'est une main ondulé explication spécifique d'une technique d'optimisation utilisée par certaines bases de données. Beaucoup ont plusieurs optimisation et performances techniques.

En fin de compte, SÉLECTIONNEZ * est utile pour les requêtes dynamiques, vous devez taper à la main, je n'avais jamais utiliser de "vrais code". L'Identification de chaque colonne donne la DB plus d'informations qu'il peut utiliser pour optimiser la requête, et vous donne un meilleur contrôle de votre code avec les modifications de schéma, etc.

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