35 votes

Pourquoi ORM est-il considéré comme bon mais "select *" comme mauvais?

N'est pas un ORM impliquent généralement de faire quelque chose comme un select *?

Si j'ai une table, MyThing, avec les colonnes A, B, C, D, etc, puis il y a généralement un objet, MyThing avec les propriétés A, B, C, D.

Il serait mal si cet objet ont été partiellement instancié par une instruction select qui ressemblait à ça, seulement de l'extraction de l'A, B, pas le C, D:

sélectionnez A, B de MyThing /* ne pas obtenir de C et D, car nous n'avons pas besoin d'eux */

mais il serait aussi mal à faire cela:

sélectionnez A, B, C, D /* obtenir toutes les colonnes de sorte que nous pouvons totalement nous instancier la MyThing de l'objet */

Ne ORM de l'hypothèse que l'accès à la base est si vite maintenant, vous n'avez pas à vous inquiéter à ce sujet et vous pouvez toujours récupérer toutes les colonnes?

Ou, avez-vous des différents MyThing objets, un pour chaque combo de colonnes qui pourrait arriver à être dans une instruction select?

EDIT: Avant de répondre à la question, veuillez lire Nicolas Piasecki et le projet de Loi Karwin réponses. Je suppose que j'ai demandé à ma question mal parce que beaucoup mal compris, mais Nicolas compris à 100%. Comme lui, je suis intéressé par d'autres réponses.


EDIT #2: les Liens qui se rapportent à cette question:

http://stackoverflow.com/questions/18655/why-do-we-need-entity-objects

http://blogs.tedneward.com/2006/06/26/The+Vietnam+De+Ordinateur+Science.aspx, en particulier la section "Partielle de l'Objet du Problème et le Temps de Charge Paradoxe"

http://groups.google.com/group/comp.object/browse_thread/thread/853fca22ded31c00/99f41d57f195f48b?

http://www.martinfowler.com/bliki/AnemicDomainModel.html

http://database-programmer.blogspot.com/2008/06/why-i-do-not-use-orm.html

65voto

Nicholas Piasecki Points 13681

Dans mon expérience limitée, les choses sont comme vous le décrivez, c'est une situation délicate et de la cop-out "ça dépend" réponse s'applique.

Un bon exemple en est la boutique en ligne que je travaille pour. Il a un Brand de l'objet, et sur la page principale du site Web, toutes les marques que le magasin vend sont répertoriés sur le côté gauche. Pour afficher ce menu, de marques, tous les besoins du site est l'entier BrandId et la chaîne BrandName. Mais l' Brand objet contient toute une cargaison d'autres propriétés, notamment une en Description de la propriété qui peut contenir sensiblement grande quantité de texte à propos de l' Brand. N'y a pas deux manières à ce sujet, le chargement de tous les de que des informations supplémentaires à propos de la marque juste pour cracher son nom dans une liste non ordonnée (1), de façon mesurable, et de ralentir considérablement, généralement en raison du grand champs de texte et (2) assez inefficace quand il s'agit de l'utilisation de la mémoire, la construction de gros des chaînes et même pas les regarder avant de les jeter.

Une option offerte par de nombreux Orm est différé charge d'une propriété. Nous avons donc pu avoir un Brand objet retourné à nous, mais qui prennent du temps et de la mémoire de gaspiller Description champ n'est pas jusqu'à ce que nous essayons d'appeler sa get accesseur. À ce stade, l'objet proxy intercepte l'appel et sucer en bas de la description à partir de la base de données juste à temps. C'est parfois assez bon, mais a m'a brûlée suffisamment de fois que personnellement, je ne le recommande pas:

  • Il est facile d'oublier que la propriété est en chargement paresseux, présentant une sélection de N+1 problème en écrivant simplement une boucle foreach. Qui sait ce qui se passe quand LINQ s'en mêle.
  • Que faire si le juste-à-temps à la base de données échoue parce que le transport a obtenu coupe le sifflet ou le réseau est allé? Je peux presque garantir que le code qui est en train de faire quelque chose d'aussi anodin qu' string desc = brand.Description ne s'attendait pas que le simple appel pour lancer une DataAccessException. Maintenant, vous avez juste s'est écrasé dans un de méchant et de manière inattendue. (Oui, j'ai regardé mon application descendre dur à cause de cela. Appris à la dure!)

Donc ce que j'ai fini par faire, c'est que dans les scénarios qui nécessitent des performances ou sont sujettes à la base de données des blocages, j'ai créer une autre interface que le site Web ou tout autre programme peut appeler pour obtenir l'accès à des blocs de données qui ont eu leur requête plans soigneusement examiné. L'architecture finit par trouver le type de cela (pardonnez l'ASCII art):

Site Web: Classes De Contrôleur
|
|---------------------------------+
 | |
Serveur d'application: IDocumentService IOrderService, IInventoryService, etc
 (Tableaux, bases de données) (Régulier OO objets, comme la Marque)
 | |
 | |
 | |
La Couche de données: (Raw ADO.NET le retour des tableaux, ("la crème entière" ORM comme NHibernate)
 Ensembles de données, des classes simples)

Je pensais que c'était de la triche, une subversion de l'OO modèle d'objet. Mais dans un sens pratique, aussi longtemps que vous faites ce raccourci pour afficher les données, je pense que c'est tout droit. Les mises à jour/inserts et qu'avez-vous encore passer par le pleinement hydratée, ORM-rempli modèle de domaine, et c'est quelque chose qui arrive beaucoup moins souvent (dans mon cas) que l'affichage de certains sous-ensembles de données. Orm comme NHibernate vous permettra de faire des projections, mais à ce stade, je ne vois pas l'intérêt de l'ORM. Ce sera probablement une procédure stockée de toute façon, l'écriture de l'ADO.NET prend deux secondes.

C'est juste mes deux cents. J'ai hâte de lire les autres réponses.

21voto

Bill Karwin Points 204877

Les gens utilisent l'ORM pour une plus grande productivité de développement, pas pour l'exécution d'optimisation de la performance. Il dépend du projet s'il est plus important de maximiser l'efficacité du développement ou de l'exécution de l'efficacité.

Dans la pratique, on peut utiliser l'ORM pour une grande productivité, et puis profil de l'application pour identifier les goulots d'étranglement, une fois que vous avez terminé. Remplacer ORM code avec des requêtes SQL personnalisées uniquement lorsque vous obtenez le plus grand coup pour le mâle.

SELECT * n'est pas mauvais si vous avez besoin, en général, toutes les colonnes d'une table. Nous ne pouvons pas généraliser que le générique est toujours de bon ou de mauvais.

edit: Re: doofledorfer commentaire... Personnellement, j'ai toujours le nom des colonnes dans une requête explicite; je n'ai jamais utiliser le caractère de remplacement dans le code de production (même si je l'utilise quand on fait des requêtes ad hoc). La question initiale est d'environ Orm -- en fait, il n'est pas rare que les ORM cadres de délivrer un SELECT * de manière uniforme, afin de remplir tous les champs dans le modèle d'objet.

L'exécution d'un SELECT * de la requête ne peut pas nécessairement que vous avez besoin de toutes ces colonnes, et il ne veut pas nécessairement dire que vous êtes négligents au sujet de votre code. Il se pourrait que l'ORM est la génération de requêtes SQL, assurez-vous que tous les champs sont disponibles dans le cas où vous en avez besoin.

6voto

Bryan Watts Points 22810

Linq to Sql, ou la mise en œuvre de IQueryable, utilise une syntaxe qui en fin de compte vous donne le contrôle sur les données sélectionnées. La définition d'une requête est d'ailleurs la définition de son jeu de résultats.

Cela évite soigneusement le select * problème en supprimant les données de forme responsabilités de l'ORM.

Par exemple, pour sélectionner toutes les colonnes:

from c in data.Customers
select c

Pour sélectionner un sous-ensemble:

from c in data.Customers
select new
{
  c.FirstName,
  c.LastName,
  c.Email
}

Pour sélectionner une combinaison:

from c in data.Customers
join o in data.Orders on c.CustomerId equals o.CustomerId
select new
{
  Name = c.FirstName + " " + c.LastName,
  Email = c.Email,
  Date = o.DateSubmitted
}

4voto

Bevan Points 20976

Il y a deux questions à prendre en considération.

Pour commencer, il est assez fréquent lors de l'utilisation d'un ORM pour la table et l'objet de très différentes "formes", c'est une des raisons pour lesquelles de nombreux outils ORM soutien assez de mappings.

Un bon exemple est le cas où une table est partiellement denormalised, avec des colonnes contenant des informations redondantes (souvent, cela est fait pour améliorer la requête ou des rapports de performance). Lorsque cela se produit, il est plus efficace pour l'ORM pour demander uniquement les colonnes qu'il exige, plutôt que d'avoir toutes les colonnes supplémentaires ramené et ignoré.

La question de savoir pourquoi "Select *" le mal est séparé, et la réponse tombe en deux moitiés.

Lors de l'exécution de "select *" le serveur de base de données n'a pas l'obligation de retourner les colonnes dans un ordre particulier, et en fait n'aurait pu raisonnablement retour les colonnes dans un ordre différent à chaque fois, mais presque pas de bases de données le faire.

Problème c'est que quand un typique développeur observe que les colonnes retournées semblent être dans un ordre cohérent, l'hypothèse est faite que les colonnes seront toujours être dans cet ordre, et puis vous avez le code faisant des suppositions injustifiées, attendant juste à l'échec. Pire, que l'échec ne peut être mortelle, mais peut simplement impliquer, dire, en utilisant l'Année de Naissance à la place du Solde du Compte.

L'autre problème avec un "Select *" tourne autour de la table à la propriété - dans de nombreuses entreprises, l'administrateur de base de contrôle le schéma, et apporte les modifications exigées par les principaux systèmes. Si votre outil est en cours d'exécution "select*", puis vous obtenez seulement les colonnes en cours - si l'administrateur a supprimé une colonne redondante que vous avez besoin, vous n'obtenez pas d'erreur et que votre code peut gaffe à venir causer toutes sortes de dommages. En demandant explicitement les champs dont vous avez besoin, vous assurer que votre système va briser plutôt que sur le processus de la mauvaise information.

4voto

NotMyself Points 7567

Je ne suis pas sûr de savoir pourquoi vous voulez partiellement hydraté objet. Étant donné une classe de Client avec des propriétés de Nom, d'Adresse, Id. Je les veux toutes pour créer un entièrement peuplée de l'objet Client.

La liste, qui pendent des Clients appelés les Commandes peuvent être paresseusement chargé lors de l'accès si la plupart des Orm. Et NHibernate de toute façon vous permet de faire des projections dans d'autres objets. Donc si vous avait dis simplement d'une liste de clients, où vous affiche l'ID et le Nom, vous pouvez créer un objet de type CustomerListDisplay et votre projet de requête HQL dans ce jeu d'objets et de n'obtenir que les colonnes dont vous avez besoin à partir de la base de données.

Les amis ne laissez pas vos amis prématuré optimiser. Hydrate parfaitement votre objet, lazy load associations. Et puis le profil de votre application à la recherche de problèmes et d'optimiser les zones à problème.

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