Question

Pourquoi l'utilisation de '*' pour créer une vue est-elle mauvaise?

Supposons que vous ayez une jointure complexe et que tous les champs puissent être utilisés quelque part.

Ensuite, il vous suffit de choisir les champs nécessaires.

SELECT field1, field2 FROM aview WHERE ...

La vue " aview " pourrait être SELECT table1. *, table2. * ... FROM table1 INNER JOIN table2 ...

Nous avons un problème si 2 champs ont le même nom dans table1 et table2.

Est-ce seulement la raison pour laquelle l'utilisation de '*' dans une vue est incorrecte?

Avec '*', vous pouvez utiliser la vue dans un contexte différent car les informations sont là.

Qu'est-ce qui me manque?

Cordialement

Était-ce utile?

La solution

Je ne pense pas qu'il y ait beaucoup de choses dans les logiciels qui soient "simplement mauvaises", mais il y a plein de choses mal utilisées de manière mauvaise: -)

L’exemple que vous donnez est une raison pour laquelle * pourrait ne pas vous donner ce que vous attendez, et je pense qu’il en existe d’autres. Par exemple, si les tables sous-jacentes changent, des colonnes sont peut-être ajoutées ou supprimées, une vue qui utilise * restera valide, mais risquera de détruire toutes les applications qui l'utilisent. Si votre vue avait nommé les colonnes de manière explicite, il était plus probable que quelqu'un repère le problème lors de la modification du schéma.

D'un autre côté, vous pouvez réellement vouloir voir votre vue avec allégresse. accepter toutes les modifications apportées aux tables sous-jacentes, auquel cas un * soyez juste ce que vous voulez.

Mise à jour: Je ne sais pas si le PO envisageait un fournisseur de base de données spécifique, mais il est maintenant clair que ma dernière remarque ne s'applique pas à tous les types. Je suis redevable à user12861 et à Jonny Leeds de l'avoir signalé et désolé, il m'a fallu plus de 6 ans pour modifier ma réponse.

Autres conseils

Bien que bon nombre des commentaires ici soient très bons et qu'ils évoquent l'un des problèmes courants liés à l'utilisation de caractères génériques dans les requêtes, tels que le déclenchement d'erreurs ou de résultats différents si les tables sous-jacentes changent, l'optimisation est un autre problème qui n'a pas été traité. Une requête qui extrait chaque colonne d'une table a tendance à ne pas être aussi efficace qu'une requête qui extrait uniquement les colonnes dont vous avez réellement besoin. Certes, il arrive que vous ayez besoin de chaque colonne et qu’une PIA majeure doive les référencer toutes, en particulier dans une table volumineuse, mais si vous n’avez besoin que d’un sous-ensemble, pourquoi paralyser votre requête avec plus de colonnes que nécessaire.

Une autre raison pour laquelle " * " Ce qui est risqué, non seulement dans les vues, mais aussi dans les requêtes, est que les colonnes peuvent changer de nom ou changer de position dans les tables sous-jacentes. L'utilisation d'un caractère générique signifie que votre vue s'adapte facilement à ces modifications sans qu'il soit nécessaire de la modifier. Toutefois, si votre application référence des colonnes par position dans le jeu de résultats ou si vous utilisez un langage dynamique qui renvoie des jeux de résultats spécifiés par nom de colonne, vous risquez de rencontrer des problèmes difficiles à résoudre.

J'évite d'utiliser le caractère générique à tout moment. Ainsi, si une colonne change de nom, une erreur s’affiche immédiatement dans la vue ou la requête et je sais où la corriger. Si une colonne change de position dans la table sous-jacente, spécifier l’ordre des colonnes dans la vue ou la requête permet de compenser cet inconvénient.

Ces autres réponses ont toutes de bons points, mais sur SQL Server au moins, elles ont aussi des points faux. Essayez ceci:

create table temp (i int, j int)
go
create view vtemp as select * from temp
go
insert temp select 1, 1
go
alter table temp add k int
go
insert temp select 1, 1, 1
go
select * from vtemp

SQL Server n'apprend pas à propos du "nouveau". colonne quand il est ajouté. Selon ce que vous voulez, cela peut être une bonne ou une mauvaise chose, mais dans tous les cas, il n’est probablement pas bon d’en dépendre. Donc, éviter cela semble être une bonne idée.

Pour moi, ce comportement étrange est la raison la plus convaincante pour éviter de sélectionner * dans les vues.

Les commentaires m’ont appris que MySQL avait un comportement similaire à celui d’Oracle (il apprendra les modifications apportées au tableau). Cette incohérence est pour moi une raison supplémentaire de ne pas utiliser select * dans les vues.

Utiliser '*' pour n'importe quoi, la production est mauvaise. C'est bien pour les requêtes ponctuelles, mais dans le code de production, vous devez toujours être aussi explicite que possible.

Pour les vues en particulier, si les colonnes sous-jacentes ont des colonnes ajoutées ou supprimées, la vue sera soit erronée, soit brisée jusqu'à ce qu'elle soit recompilée.

L'utilisation de SELECT * dans la vue n'entraîne pas une surcharge de performances si les colonnes ne sont pas utilisées en dehors de la vue - l'optimiseur les optimisera; SELECT * FROM TheView peut peut-être gaspiller de la bande passante, comme à chaque fois que vous extrayez plus de colonnes sur une connexion réseau.

En fait, j’ai constaté que les vues reliant la quasi-totalité des colonnes d’un grand nombre de tables de mon entrepôt de données n’entraînaient aucun problème de performances, même si relativement peu de ces colonnes étaient demandées en dehors de la vue. L’optimiseur gère cela correctement et est capable d’enfoncer très bien les critères de filtrage externes dans la vue.

Cependant, pour toutes les raisons données ci-dessus, j'utilise très rarement SELECT * .

J'ai des processus métier dans lesquels plusieurs CTE sont construits les uns sur les autres, construisant efficacement des colonnes dérivées à partir de colonnes dérivées (qui, espérons-le, seront un jour refactorisées à mesure que l'entreprise rationalise et simplifie ces calculs), et dans ce cas, toutes les colonnes doivent être supprimées à chaque fois et j'utilise SELECT * - mais SELECT * n'est pas utilisé au niveau de la couche de base, mais uniquement entre les deux. premier CTE et le dernier.

La situation sur SQL Server est encore pire que la réponse de @ user12861 ne l’implique: si vous utilisez SELECT * sur plusieurs tables, l’ajout de colonnes à une table référencée plus tôt dans la requête entraînera afficher les valeurs des nouvelles colonnes sous la forme des anciennes colonnes. Voir l'exemple ci-dessous:

-- create two tables
CREATE TABLE temp1 (ColumnA INT, ColumnB DATE, ColumnC DECIMAL(2,1))
CREATE TABLE temp2 (ColumnX INT, ColumnY DATE, ColumnZ DECIMAL(2,1))
GO


-- populate with dummy data
INSERT INTO temp1 (ColumnA, ColumnB, ColumnC) VALUES (1, '1/1/1900', 0.5)
INSERT INTO temp2 (ColumnX, ColumnY, ColumnZ) VALUES (1, '1/1/1900', 0.5)
GO


-- create a view with a pair of SELECT * statements
CREATE VIEW vwtemp AS 
SELECT *
FROM temp1 INNER JOIN temp2 ON 1=1
GO


-- SELECT showing the columns properly assigned
SELECT * FROM vwTemp 
GO


-- add a few columns to the first table referenced in the SELECT 
ALTER TABLE temp1 ADD ColumnD varchar(1)
ALTER TABLE temp1 ADD ColumnE varchar(1)
ALTER TABLE temp1 ADD ColumnF varchar(1)
GO


-- populate those columns with dummy data
UPDATE temp1 SET ColumnD = 'D', ColumnE = 'E', ColumnF = 'F'
GO


-- notice that the original columns have the wrong data in them now, causing any datatype-specific queries (e.g., arithmetic, dateadd, etc.) to fail
SELECT *
FROM vwtemp
GO

-- clean up
DROP VIEW vwTemp
DROP TABLE temp2
DROP TABLE temp1

C’est parce que vous n’avez pas toujours besoin de toutes les variables et que vous pensez bien à ce dont vous avez spécifiquement besoin.

Par exemple, il ne sert à rien d’obtenir tous les mots de passe hachés de la base de données lors de la création d’une liste d’utilisateurs sur votre site. Ainsi, une sélection * serait improductive.

Il était une fois, j'ai créé une vue sur une table d'une autre base de données (sur le même serveur) avec

Select * From dbname..tablename

Puis un jour, une colonne a été ajoutée à la table ciblée. La vue a commencé à renvoyer des résultats totalement incorrects jusqu'à ce qu'elle soit redéployée.

Totalement incorrect: pas de lignes.

C'était sur SQL Server 2000.

Je suppose que cela est dû aux valeurs syscolumns que la vue a capturées, même si j'ai utilisé *.

Une requête SQL est fondamentalement une unité fonctionnelle conçue par un programmeur pour être utilisée dans un certain contexte. Pour une stabilité et une capacité de support à long terme (éventuellement par une personne autre que vous), toute unité fonctionnelle doit exister dans un but précis et être expliquée de manière raisonnable (ou documentée), en particulier pourquoi chaque élément de données.

Si je devais avoir deux ans à partir de maintenant avec le besoin ou le désir de modifier votre requête, je m'attendrais à le traiter assez attentivement avant de pouvoir croire que je pourrais le gâcher. Ce qui signifie que j'aurais besoin de comprendre pourquoi toutes les colonnes sont appelées. (Ceci est encore plus évident si vous essayez de réutiliser la requête dans plusieurs contextes. Ce qui est généralement problématique, pour des raisons similaires.) Si je voyais dans la sortie des colonnes que je ne pourrais pas relier à une fin quelconque , Je suis à peu près sûr de ne pas comprendre ce qu’il a fait, pourquoi et quelles en seraient les conséquences.

C'est généralement une mauvaise idée d'utiliser *. Certains moteurs de certification de code marquent cela comme un avertissement et vous conseillent de ne mentionner explicitement que les colonnes nécessaires. L'utilisation de * peut conduire à des poux de performance, car il se peut que vous n'ayez besoin que de quelques colonnes et non de toutes. Cependant, dans certains cas, l'utilisation de * est idéale. Imaginez que, quoi que vous utilisiez, à l'aide de l'exemple que vous avez fourni, pour cette vue (vue), vous ayez toujours besoin de toutes les colonnes de ces tables. À l'avenir, lorsqu'une colonne est ajoutée, vous n'avez pas besoin de modifier la vue. Cela peut être bon ou mauvais selon le cas auquel vous faites face.

Je pense que cela dépend de la langue que vous utilisez. Je préfère utiliser select * lorsque le langage ou le pilote de base de données renvoie un dict (Python, Perl, etc.) ou un tableau associatif (PHP) des résultats. Cela rend votre code beaucoup plus facile à comprendre si vous vous référez aux colonnes par leur nom plutôt que comme un index dans un tableau.

Personne ne semble l'avoir mentionné, mais dans SQL Server, vous pouvez également configurer votre vue avec le attribut de schématisation .

Ceci empêche toute modification des tables de base (y compris leur suppression) qui pourrait affecter la définition de la vue.

Cela peut vous être utile dans certaines situations. Je me rends compte que je n’ai pas répondu exactement à votre question, mais j’ai pensé la mettre en évidence néanmoins.

Et si vous utilisez des jointures avec select *, cela signifie automatiquement que vous renvoyez plus de données que nécessaire, les données des champs de jointure étant répétées. C'est un gaspillage de base de données et de ressources réseau.

Si vous êtes assez naïf pour utiliser des vues appelant d'autres vues, l'utilisation de select * peut les rendre encore plus performants (cette technique est mauvaise pour la performance seule. Le fait d'appeler plusieurs colonnes dont vous n'avez pas besoin ne fait qu'empirer les choses. ).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top