Entity Framework convient-il aux sites Web à fort trafic?


176

Entity Framework 4 est-il une bonne solution pour un site Web public pouvant potentiellement atteindre 1 000 visites / seconde?

À mon sens, EF est une solution viable pour la plupart des sites Web plus petits ou intranet, mais ne s'adapte pas facilement à un site Web populaire (je sais que SO utilise LINQ to SQL, mais ... j'aimerais davantage d'exemples / de preuves. ..)

Je me trouve maintenant à la croisée des chemins, que ce soit en choisissant une approche purement ADO.NET ou EF4. Pensez-vous que l'amélioration de la productivité des développeurs avec EF vaut la perte de performance et l'accès granulaire d'ADO.NET (avec les procédures stockées)? Un site Web à fort trafic pourrait-il rencontrer des problèmes graves, utilisait-il EF?

Merci d'avance.


1
Vous ne comprenez pas la mise à l'échelle. La mise à l'échelle signifie un débit 10x lorsque vous ajoutez une capacité 10x. Pourquoi EF empêcherait-il cela? Il ajoute un facteur de surcharge constant à toute charge de travail de base de données.
usr

Réponses:


152

Cela dépend un peu de l'abstraction dont vous avez besoin . Tout est un compromis par exemple, EF et NHibernate introduisent une grande flexibilité pour représenter les données dans les modèles intéressants et exotiques - mais par conséquent , ils font ajouter les frais généraux. Frais généraux visibles.

Si vous n'avez pas besoin de pouvoir basculer entre les fournisseurs de base de données, et différentes dispositions de table par client, et si vos données sont principalement lues , et si vous n'avez pas besoin d'utiliser le même modèle dans EF, SSRS , ADO.NET Data Services, etc. - si vous voulez des performances absolues comme mesure clé, vous pourriez faire bien pire que regarder Dapper . Dans nos tests basés sur LINQ-to-SQL et EF, nous avons constaté que EF est nettement plus lent en termes de performances de lecture brute, probablement à cause des couches d'abstraction (entre le modèle de stockage, etc.) et de la matérialisation.

Ici, chez SO, nous sommes obsessionnels-compulsifs à propos de la performance brute, et nous sommes heureux de prendre le flambeau du développement de perdre de l'abstraction pour gagner de la vitesse. En tant que tel, notre outil principal pour interroger la base de données est Dapper . Cela nous permet même d’utiliser notre modèle LINQ-to-SQL préexistant, mais simplement: il est beaucoup plus rapide. Dans les tests de performance, il s’agit essentiellement des mêmes performances que l’écriture manuelle de tout le code ADO.NET (paramètres, lecteurs de données, etc.), mais sans risque de se tromper de nom de colonne. Il est cependant basé sur SQL (bien qu'il soit heureux d'utiliser les SPROC si c'est votre poison choisi). L'avantage est qu'il n'y a pas de traitement supplémentaire en jeu, mais il est un système pour les personnes qui aiment SQL. Ce que je considère: pas une mauvaise chose!

Une requête typique, par exemple, pourrait être:

int customerId = ...
var orders = connection.Query<Order>(
    "select * from Orders where CustomerId = @customerId ",
    new { customerId }).ToList();

ce qui est pratique, sûr pour l'injection, etc. - mais sans tonnes de lecteur de données goo. Notez que s'il peut gérer à la fois des partitions horizontales et verticales pour charger des structures complexes, il ne supportera pas le chargement paresseux (mais: nous sommes de grands fans du chargement très explicite - moins de surprises).

Remarque dans cette réponse, je ne dis pas que l'EF n'est pas adapté au travail en gros volume; tout simplement: je sais que dapper est à la hauteur.


25
+1 pour dapper. L'utilisation d'un ORM complexe pour les modèles en lecture est tout simplement inutile. L'approche que nous adoptons maintenant consiste à utiliser un ORM pour notre modèle de domaine (où les éléments ORM sophistiqués sont réellement utiles) et un dapper pour notre modèle de lecture. Cela fait pour les applications super rapides.

2
@Marc, merci pour cette excellente réponse - je peux enfin prendre ma décision en toute confiance! Je vais certainement examiner Dapper plus en détail plus tard. Vraiment comme il ne s'agit que d'un fichier :)

3
J'ai écrit mon propre ORM. C'est lent. J'ai regardé Dapper et l'ai aimé. Maintenant, j'utilise dapper pour toutes mes lectures et mon propre ORM pour les insertions (qui prend en charge FK, les transactions et toutes les bonnes choses). C'est le code le plus lisible que j'ai jamais écrit.

2
@ acidzombie24 dapper prend en charge les transactions, et la partie contrib de dapper (qui ne fait pas partie du déploiement du nuget) bénéficie d'options d'insertion, etc. Il suffit de mentionner pour être complet. Je suis content que Dapper soit pratique.
Marc Gravell

1
@anyname Je n'ai jamais fait de cours vidéo sur aucun sujet; il y a des vidéos, mais pas par moi. J'ai tendance à être un mot écrit
Marc Gravell

217

La question "quel ORM devrais-je utiliser" vise vraiment le sommet d'un énorme iceberg en ce qui concerne la stratégie globale d'accès aux données et l'optimisation des performances dans une application à grande échelle.

Toutes les choses suivantes (en gros par ordre d'importance) vont affecter le débit, et elles sont toutes gérées (parfois de différentes manières) par la plupart des principaux cadres ORM:

  1. Conception et maintenance de bases de données

    C’est de loin le principal facteur déterminant du débit d’une application ou d’un site Web gérée par les données, et il est souvent totalement ignoré des programmeurs.

    Si vous n'utilisez pas les techniques de normalisation appropriées, votre site est condamné. Si vous n'avez pas de clé primaire, presque chaque requête sera lente. Si vous utilisez des anti-modèles connus, tels que l'utilisation de tables pour les paires clé-valeur (valeur d'entité-attribut AKA) sans raison valable, vous exploserez le nombre de lectures et d'écritures physiques.

    Si vous ne tirez pas parti des fonctionnalités FILESTREAMfournies par la base de données, telles que la compression de page, le stockage (pour les données binaires), les SPARSEcolonnes, les hierarchyidhiérarchies, etc. (tous les exemples SQL Server), vous ne verrez nulle part près de la une performance que vous pourriez voir.

    Vous devriez commencer à vous soucier de votre stratégie d'accès aux données après avoir conçu votre base de données et vous être convaincu qu'elle est aussi performante que possible, du moins pour le moment.

  2. Eager vs. Lazy Loading

    La plupart des ORM utilisaient une technique appelée " chargement paresseux pour relations", ce qui signifie que par défaut, il charge une entité (ligne de tableau) à la fois et effectue un aller-retour vers la base de données chaque fois qu'elle doit charger un ou plusieurs éléments associés (étrangers). touche) rangées.

    Ce n'est pas une bonne ou une mauvaise chose, cela dépend plutôt de ce qui sera réellement fait avec les données et de ce que vous savez en amont. Parfois, le chargement paresseux est absolument la bonne chose à faire. NHibernate, par exemple, peut décider de ne rien interroger du tout et de générer simplement un proxy pour un identifiant particulier. Si tout ce dont vous avez besoin est l’ID lui-même, pourquoi devrait-il en demander plus? D'autre part, si vous essayez d'imprimer une arborescence de chaque élément d'une hiérarchie à 3 niveaux, le chargement différé devient une opération O (N²), ce qui est extrêmement mauvais pour la performance.

    L’utilisation de «SQL pur» (c’est-à-dire des requêtes ADO.NET brutes / procédures stockées) présente l’avantage intéressant de vous obliger à déterminer exactement quelles données sont nécessaires pour afficher un écran ou une page donnés. Les ORM et les fonctionnalités de chargement paresseux ne vous empêchent pas de le faire, mais vous donnent la possibilité d'être ... bien, paresseux et d'exploser accidentellement le nombre de requêtes que vous exécutez. Vous devez donc comprendre les fonctionnalités de chargement rapide de vos ORM et être toujours vigilant quant au nombre de requêtes que vous envoyez au serveur pour une requête de page donnée.

  3. Mise en cache

    Tous les principaux ORM conservent un cache de premier niveau, AKA "cache d'identité", ce qui signifie que si vous demandez deux fois la même entité par son ID, elle ne nécessite pas de deuxième aller-retour, et également (si vous avez conçu votre base de données correctement). ) vous donne la possibilité d'utiliser une concurrence optimiste.

    Le cache L1 est assez opaque dans L2S et EF, il faut en quelque sorte avoir confiance que cela fonctionne. NHibernate est plus explicite à ce sujet ( Get/ Loadvs. Query/ QueryOver). Néanmoins, tant que vous tenterez d’interroger autant que possible par ID, tout devrait bien se passer ici. Beaucoup de gens oublient le cache L1 et cherchent à plusieurs reprises la même entité sous un autre nom que son identifiant (c'est-à-dire un champ de recherche). Si vous avez besoin de le faire, vous devez enregistrer l'ID ou même l'entité entière pour les recherches futures.

    Il existe également un cache de niveau 2 ("cache de requête"). NHibernate a cette fonction intégrée. Linq to SQL et Entity Framework ont des requêtes compilées , ce qui peut aider à réduire un peu les charges du serveur d'applications en compilant l'expression de requête elle-même, mais elle ne met pas les données en cache. Microsoft semble considérer cela comme un problème d’application plutôt que comme un problème d’accès aux données, ce qui constitue un point faible majeur à la fois pour L2S et EF. Inutile de dire que c'est aussi un point faible du SQL "brut". Pour obtenir de très bonnes performances avec pratiquement tous les ORM autres que NHibernate, vous devez implémenter votre propre façade de mise en cache.

    Il existe également une "extension" de cache L2 pour EF4, ce qui est correct , mais pas vraiment un remplacement en gros pour un cache au niveau de l'application.

  4. Nombre de requêtes

    Les bases de données relationnelles sont basées sur des ensembles de données. Ils sont très efficaces pour produire de grandes quantités de données en peu de temps, mais ils sont loin d’être aussi performants en termes de temps d’ attente des requêtes, car chaque commande comporte un certain temps système. Une application bien conçue doit exploiter les atouts de ce SGBD, tenter de minimiser le nombre de requêtes et de maximiser la quantité de données qu'elles contiennent.

    Maintenant, je ne dis pas d'interroger la base de données complète lorsque vous n'avez besoin que d'une seule ligne. Ce que je veux dire est, si vous avez besoin Customer, Address, Phone, CreditCardet des Orderlignes toutes en même temps afin de servir une seule page, alors vous devriez demander à tous en même temps, ne pas exécuter chaque requête séparément. Parfois c'est pire que ça, vous verrez du code qui interroge le même Customerenregistrement 5 fois de suite, d'abord pour obtenir le Id, puis le Name, puis le EmailAddress, puis ... c'est ridiculement inefficace.

    Même si vous devez exécuter plusieurs requêtes qui fonctionnent toutes sur des ensembles de données complètement différents, il est généralement plus efficace de tout envoyer à la base de données sous la forme d'un "script" unique et de lui renvoyer plusieurs ensembles de résultats. Ce qui vous préoccupe, ce sont les frais généraux, et non la quantité totale de données.

    Cela peut sembler logique, mais il est souvent très facile de perdre le fil de toutes les requêtes en cours d’exécution dans diverses parties de l’application; votre fournisseur d’appartenance interroge les tables utilisateur / rôle, votre action d’en-tête interroge le panier, votre action Menu interroge la table de plan du site, votre action Barre latérale interroge la liste de produits sélectionnée, puis peut-être que votre page est divisée en plusieurs zones autonomes interrogez séparément les tables Historique des commandes, Récemment consultées, Catégorie et Inventaire, et avant de vous en rendre compte, vous exécutez 20 requêtes avant même de pouvoir commencer à servir la page. Cela détruit complètement les performances.

    Certains cadres - et je pense principalement à NHibernate ici - sont extrêmement intelligents à cet égard et vous permettent d’utiliser un système appelé futures qui regroupe des requêtes entières et tente de les exécuter tous à la fois, à la dernière minute possible. Autant que je sache, vous êtes autonome si vous souhaitez le faire avec l’une des technologies Microsoft; vous devez l'intégrer dans votre logique d'application.

  5. Indexation, prédicats et projections

    Au moins 50% des développeurs à qui je parle et même certains administrateurs de base de données semblent avoir des problèmes avec le concept d'index de couverture. Ils pensent: "Eh bien, la Customer.Namecolonne est indexée, donc chaque recherche que je fais sur le nom devrait être rapide." Sauf que cela ne fonctionne de cette façon que si l' Nameindex couvre la colonne que vous recherchez. Dans SQL Server, cela se fait INCLUDEdans l' CREATE INDEXinstruction.

    Si vous utilisez naïvement SELECT *partout - et c'est plus ou moins ce que fera chaque ORM à moins d'indication explicite contraire utilisant une projection - alors le SGBD peut très bien choisir d'ignorer complètement vos index car ils contiennent des colonnes non couvertes. Une projection signifie par exemple qu'au lieu de faire ceci:

    from c in db.Customers where c.Name == "John Doe" select c
    

    Vous faites cela à la place:

    from c in db.Customers where c.Name == "John Doe"
    select new { c.Id, c.Name }
    

    Et cette volonté, pour la plupart des ORM modernes, instruisent à aller seulement et interroger les Idet Namecolonnes qui sont vraisemblablement couvertes par l'indice (mais pas Email, LastActivityDateou tout autre colonnes se sont passées en tenir là - dedans).

    Il est également très facile de supprimer complètement les avantages de l'indexation en utilisant des prédicats inappropriés. Par exemple:

    from c in db.Customers where c.Name.Contains("Doe")
    

    ... semble presque identique à notre requête précédente, mais aboutira en fait à une analyse complète de la table ou de l'index car elle se traduit par LIKE '%Doe%'. De même, une autre requête qui semble étrangement simple est:

    from c in db.Customers where (maxDate == null) || (c.BirthDate >= maxDate)
    

    En supposant que vous ayez un index BirthDate, ce prédicat a de bonnes chances de le rendre complètement inutile. Notre programmeur hypothétique ici a évidemment tenté de créer une sorte de requête dynamique ("ne filtrer que la date de naissance si ce paramètre a été spécifié"), mais ce n'est pas la bonne façon de le faire. Écrit comme ceci à la place:

    from c in db.Customers where c.BirthDate >= (maxDate ?? DateTime.MinValue)
    

    ... maintenant le moteur de base de données sait comment paramétrer ceci et faire une recherche d'index. Une modification mineure, apparemment insignifiante, de l'expression de requête peut affecter considérablement les performances.

    Malheureusement, en général, LINQ facilite trop l'écriture de mauvaises requêtes, car les fournisseurs sont parfois en mesure de deviner ce que vous avez essayé de faire et d'optimiser la requête, mais ils ne le sont parfois pas. Vous obtenez donc des résultats frustrants et incohérents qui auraient été aveuglément évidents (pour un administrateur de base de données expérimenté, de toute façon) si vous veniez d’écrire du vieux code clair.

    En gros, vous devez garder un œil attentif sur le code SQL généré et les plans d’exécution qu’ils génèrent. Si vous n’obtenez pas les résultats escomptés, n’ayez pas peur de contourner le code. Couche ORM de temps en temps et coder manuellement le code SQL. Cela vaut pour n'importe quel ORM, pas seulement EF.

  6. Transactions et verrouillage

    Avez-vous besoin d’afficher des données actuelles jusqu’à la milliseconde? Peut-être - ça dépend - mais probablement pas. Malheureusement, Entity Framework ne vous en donne pasnolock , vous ne pouvez l'utiliser READ UNCOMMITTEDqu'au niveau de la transaction (pas au niveau de la table). En fait, aucun des ORM n'est particulièrement fiable à ce sujet; si vous voulez effectuer des lectures modifiées, vous devez descendre au niveau SQL et écrire des requêtes ad-hoc ou des procédures stockées. Il s’agit donc encore une fois de la facilité avec laquelle vous pouvez le faire dans le cadre.

    Entity Framework a parcouru un long chemin à cet égard - la version 1 de EF (dans .NET 3.5) était affreuse, ce qui rendait incroyablement difficile la traversée de l'abstraction des "entités", mais vous avez maintenant ExecuteStoreQuery et Translate , donc c'est vraiment pas mal. Faites-vous des amis avec ces gars parce que vous les utiliserez beaucoup.

    Il y a aussi la question du verrouillage en écriture et des blocages, ainsi que de la pratique courante consistant à conserver les verrous dans la base de données le moins longtemps possible. À cet égard, la plupart des ORM (y compris Entity Framework) ont tendance à être meilleurs que le SQL brut, car ils encapsulent le modèle d' unité de travail , qui en EF correspond à SaveChanges . En d'autres termes, vous pouvez "insérer" ou "mettre à jour" ou "supprimer" des entités au contenu de votre coeur, à tout moment, en sachant qu'aucune modification ne sera réellement poussée dans la base de données tant que vous ne aurez pas validé l'unité de travail.

    Notez qu'un UOW n'est pas analogue à une transaction longue. L’UOW utilise toujours les fonctionnalités de simultanéité optimistes de l’ORM et suit tous les changements en mémoire . Aucune instruction DML n'est émise avant la validation finale. Cela permet de réduire au maximum les délais de transaction. Si vous construisez votre application en utilisant du SQL brut, il est assez difficile d’obtenir ce comportement différé.

    Ce que cela signifie pour EF en particulier: Rendez vos unités de travail aussi grossières que possible et ne les engagez pas avant que vous en ayez absolument besoin. Faites cela et vous vous retrouverez avec des conflits de verrous bien moins importants que si vous utilisiez des commandes ADO.NET individuelles à des moments aléatoires.

En conclusion:

EF convient parfaitement aux applications à trafic élevé / hautes performances, tout comme n'importe quel autre framework convient parfaitement aux applications à trafic élevé / hautes performances. Ce qui compte, c'est comment vous l'utilisez. Voici une comparaison rapide des frameworks les plus populaires et de leurs fonctionnalités en termes de performances (légende: N = Non pris en charge, P = Partiel, Y = oui / pris en charge):

                                | L2S | EF1 | EF4 | NH3 | ADO
                                +-----+-----+-----+-----+-----
Lazy Loading (entities)         |  N  |  N  |  N  |  Y  |  N
Lazy Loading (relationships)    |  Y  |  Y  |  Y  |  Y  |  N
Eager Loading (global)          |  N  |  N  |  N  |  Y  |  N
Eager Loading (per-session)     |  Y  |  N  |  N  |  Y  |  N
Eager Loading (per-query)       |  N  |  Y  |  Y  |  Y  |  Y
Level 1 (Identity) Cache        |  Y  |  Y  |  Y  |  Y  |  N
Level 2 (Query) Cache           |  N  |  N  |  P  |  Y  |  N
Compiled Queries                |  Y  |  P  |  Y  |  N  | N/A
Multi-Queries                   |  N  |  N  |  N  |  Y  |  Y
Multiple Result Sets            |  Y  |  N  |  P  |  Y  |  Y
Futures                         |  N  |  N  |  N  |  Y  |  N
Explicit Locking (per-table)    |  N  |  N  |  N  |  P  |  Y
Transaction Isolation Level     |  Y  |  Y  |  Y  |  Y  |  Y
Ad-Hoc Queries                  |  Y  |  P  |  Y  |  Y  |  Y
Stored Procedures               |  Y  |  P  |  Y  |  Y  |  Y
Unit of Work                    |  Y  |  Y  |  Y  |  Y  |  N

Comme vous pouvez le constater, EF4 (la version actuelle) n’est pas trop mal loti, mais ce n’est probablement pas le meilleur choix si les performances sont votre principale préoccupation. NHibernate est beaucoup plus mature dans ce domaine et même Linq to SQL fournit des fonctionnalités améliorant les performances que EF n’a toujours pas. Raw ADO.NET sera souvent plus rapide pour des scénarios d’accès aux données très spécifiques , mais, lorsque vous réunissez tous les éléments, il n’offre vraiment pas les avantages importants que vous retirez des différents frameworks.

Et, juste pour m'assurer que je ressemble à un disque brisé, rien de tout cela n'a aucune importance si vous ne concevez pas correctement vos stratégies de base de données, d'applications et d'accès aux données. Tous les éléments du graphique ci-dessus visent à améliorer les performances au-delà de la valeur de base. la plupart du temps, c'est la ligne de base elle-même qui nécessite le plus d'amélioration.


38
Quelle réponse géniale et complète!

2
+1 (plus si je pouvais) - une des meilleures réponses que j'ai vues depuis un moment ici et j'ai appris une chose ou deux - merci de partager cela!
BrokenGlass

1
C'est une excellente réponse même si je ne suis pas d'accord avec tout ce qui est mentionné. Le tableau comparant les ORM n'est pas toujours correct. Qu'est-ce que le chargement paresseux des entités? Voulez-vous dire des colonnes chargées paresseux? Cela est pris en charge dans L2S. Pourquoi pensez-vous que NH ne prend pas en charge les requêtes compilées? Je pense que les requêtes HQL nommées peuvent être pré-compilées. EF4 ne prend pas en charge plusieurs jeux de résultats.
Ladislav Mrnka

11
Je suis tout à fait en désaccord avec la déclaration non qualifiée "EF est tout à fait acceptable pour les applications à trafic élevé / hautes performances", nous avons vu à plusieurs reprises que ce n'était pas le cas. Certes, nous ne sommes peut-être pas d’accord sur le sens du mot "haute performance", mais par exemple, l’optimisation des pages Web à 500 ms et le dépassement de 400 ms inexplicablement dans le cadre (et seulement 10 ms en frappant SQL) ne sont pas "corrects" dans certaines situations, c'est carrément inacceptable pour notre équipe de développement.
Nick Craver

1
Remarque simple sur les contrats à terme dans EF. Ils ne sont pas officiellement fournis par l'équipe MS EF, mais peuvent être réalisés via des projets tiers définissant les extensions Future <> d'IQueryable <>. Par exemple, EntityFramework.Extended by LoreSoft, disponible dans NuGet. Mes tests personnels dans les applications de production montrent un gain de performances jusqu'à 10 fois lorsque vous empaquetez des dizaines de requêtes non dépendantes (toutes les requêtes peuvent être exécutées en parallèle, personne ne requiert le résultat d'un précédent) en un seul lot avec Future. De plus, AsNoTracking () améliore considérablement les performances lors de la lecture de nombreux enregistrements, sans mise à jour ultérieure.
David Oliván Ubieto

38

Edit: Basé sur la réponse géniale de @Aaronaught, j'ajoute quelques points en termes de performances ciblées avec EF. Ces nouveaux points sont préfixés par Edit.


L’amélioration la plus importante des performances des sites Web à fort trafic est obtenue par la mise en cache (en évitant d’abord tout traitement de serveur Web ou interrogation de base de données) suivie d’un traitement asynchrone pour éviter le blocage de threads lors de l’exécution des requêtes de base de données.

Il n’ya pas de réponse à toute épreuve à votre question car elle dépend toujours des exigences d’application et de la complexité des requêtes. La vérité est que la productivité des développeurs avec EF cache une complexité qui, dans de nombreux cas, conduit à une utilisation incorrecte de EF et à des performances terribles. L'idée de pouvoir exposer une interface abstraite de haut niveau pour l'accès aux données et que cela fonctionnera sans problème dans tous les cas ne fonctionnera pas. Même avec ORM, vous devez savoir ce qui se passe derrière l'abstraction et comment l'utiliser correctement.

Si vous n’avez pas d’expérience antérieure avec EF, vous devrez faire face à de nombreux défis en matière de performance. Vous pouvez faire beaucoup plus d’erreurs lorsque vous travaillez avec EF en comparant à ADO.NET. En outre, beaucoup de traitements supplémentaires sont effectués dans EF. Par conséquent, EF sera toujours beaucoup plus lent que ADO.NET natif - vous pouvez le mesurer en appliquant simplement une preuve de concept.

Si vous souhaitez obtenir les meilleures performances d'EF, vous devrez probablement:

  • Révisez très soigneusement votre accès aux données avec le profileur SQL et passez en revue vos requêtes LINQ si elles utilisent correctement Linq-to-entity au lieu de Linq-to-objects
  • Utilisez très soigneusement les fonctionnalités avancées d'optimisation EF telles que MergeOption.NoTracking
  • Utiliser ESQL dans certains cas
  • Requêtes de pré-compilation souvent exécutées
  • Pensez à tirer parti de l'encapsuleur EF Caching pour obtenir une "fonctionnalité de cache de second niveau" pour certaines requêtes.
  • Utiliser des vues SQL ou des requêtes SQL personnalisées mappées (nécessite la maintenance manuelle du fichier EDMX) dans certains scénarios pour les projections ou les agrégations fréquemment utilisées nécessitant des améliorations de performances.
  • Utilisez du SQL natif et des procédures stockées pour certaines requêtes qui n'offrent pas des performances suffisantes lorsqu'elles sont définies dans Linq ou ESQL
  • Edit: utilisez soigneusement les requêtes - chaque requête effectue un aller-retour séparé vers la base de données. EFv4 ne comporte pas de traitement par lots de requêtes car il ne peut pas utiliser plusieurs jeux de résultats par commande de base de données exécutée. EFv4.5 prend en charge plusieurs jeux de résultats pour les procédures stockées mappées.
  • Edit: Travaillez soigneusement avec les modifications de données. Encore une fois, EF manque complètement de batch de commandes . Donc, dans ADO.NET, vous pouvez utiliser un seul SqlCommandcontenant plusieurs insertions, mises à jour ou suppressions, mais avec EF, chacune de ces commandes sera exécutée dans un aller-retour séparé vers la base de données.
  • Éditer: Travaillez soigneusement avec la carte d'identité / le cache d'identité. EF dispose d'une méthode spéciale ( GetByKeydans l'API ObjectContext ou Finddans l'API DbContext) pour interroger d'abord le cache. Si vous utilisez Linq-to-entity ou ESQL, cela créera un aller-retour à la base de données, après quoi il retournera l'instance existante à partir du cache.
  • Edit: utilisez avec précaution le chargement. Ce n'est pas toujours une solution gagnant-gagnant car elle produit un énorme jeu de données . Comme vous pouvez le constater, la complexité est considérable et l’essentiel. ORM simplifie la cartographie et la matérialisation, mais s’agissant de la performance, elle sera beaucoup plus complexe et vous devrez faire des compromis.

Je ne suis pas sûr que SO utilise toujours L2S. Ils ont développé un nouvel ORM Open Source appelé Dapper et je pense que le point principal de ce développement était l'amélioration des performances.


Ladislav, c'est une réponse très utile. C'est la première fois que j'entends parler de Dapper (et par conséquent de PetaPoco, Massive) - et cela semble être une idée intéressante.

1
SO semble utiliser un mélange de LINQ to SQL et de Dapper maintenant: samsaffron.com/archive/2011/03/30/… Quote: "Nous utilisons notre nouvel ORM [Dapper] pour un problème spécifique: le mappage de SQL paramétrée en objets métier .Nous ne l’utilisons pas comme un ORM complet. Il ne fait pas de relations ni d’autres sifflements. Cela nous permet de continuer à utiliser LINQ-2-SQL là où les performances n’importent pas et de transférer tous nos SQL en ligne pour utiliser notre mappeur, car il est plus rapide et plus flexible. "

5
@Slauma eh bien, c’est une déclaration d’il ya des mois. En général, tous les nouveaux travaux sur les SO sont effectués dans Dapper. Par exemple, une nouvelle table que j’ai ajoutée aujourd’hui ne figure même pas dans le fichier dbml.
Sam Saffron

1
@Sam: Existe-t-il un nouveau blog sur la stratégie actuelle d'accès aux données sur les SO? Serait très intéressant! Dapper a-t-il été prolongé entre-temps? Je croyais comprendre que Dapper n’était pas un ORM complet, qu’il ne prenait pas en charge les relations - qu’en était-il des mises à jour, des insertions, des suppressions, des transactions, du suivi des modifications, etc.?
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.