J'ai suivi le mantra «Ne pas optimiser prématurément» et codé mon service WCF en utilisant Entity Framework.
Cependant, j'ai profilé les performances et Entity Framework est trop lent. (Mon application traite 2 messages en 1,2 seconde environ, alors que l'application (héritée) que je réécrit fait 5 à 6 messages en même temps (l'application héritée appelle sprocs pour son accès à la base de données).)
Mon profilage pointe vers Entity Framework prenant la majeure partie du temps par message.
Alors, quelles sont mes options?
Existe-t-il de meilleurs ORM?
(Quelque chose qui prend simplement en charge la lecture et l'écriture normales des objets et le fait rapidement.)Existe-t-il un moyen de rendre Entity Framework plus rapide?
( Remarque : quand je dis plus vite, je veux dire sur le long terme, pas le premier appel. (Le premier appel est lent (15 secondes pour un message), mais ce n'est pas un problème. J'ai juste besoin que ce soit rapide pour le reste. des messages.)Une troisième option mystérieuse qui m'aidera à obtenir plus de vitesse de mon service.
REMARQUE: la plupart de mes interactions DB sont Créer et Mettre à jour. Je fais très très peu de sélection et de suppression.
la source
Réponses:
Vous devez commencer par profiler les commandes SQL réellement émises par Entity Framework. En fonction de votre configuration (POCO, entités Self-Tracking), il y a beaucoup de place pour les optimisations. Vous pouvez déboguer les commandes SQL (qui ne devraient pas différer entre les modes de débogage et de version) à l'aide de la
ObjectSet<T>.ToTraceString()
méthode. Si vous rencontrez une requête qui nécessite une optimisation supplémentaire, vous pouvez utiliser certaines projections pour donner à EF plus d'informations sur ce que vous essayez d'accomplir.Exemple:
Peut être remplacé par:
Je viens de taper cela de ma tête, donc ce n'est pas exactement comment cela serait exécuté, mais EF fait en fait de belles optimisations si vous lui dites tout ce que vous savez sur la requête (dans ce cas, nous aurons besoin de la catégorie- des noms). Mais ce n'est pas comme un chargement hâtif (db.Products.Include ("Categories")) car les projections peuvent réduire davantage la quantité de données à charger.
la source
Le fait est que les produits tels que Entity Framework seront TOUJOURS lents et inefficaces, car ils exécutent beaucoup plus de code.
Je trouve aussi ridicule que les gens suggèrent d'optimiser les requêtes LINQ, de regarder le SQL généré, d'utiliser des débogueurs, de pré-compiler, de prendre de nombreuses étapes supplémentaires, etc. c'est-à-dire perdre beaucoup de temps. Personne ne dit - Simplifiez! Tout le monde veut compliquer davantage les choses en prenant encore plus de mesures (perdre du temps).
Une approche de bon sens serait de ne pas utiliser du tout EF ou LINQ. Utilisez du SQL brut. Il n'y a rien de mal à cela. Ce n'est pas parce qu'il y a une mentalité de troupeau parmi les programmeurs et qu'ils ressentent le besoin d'utiliser chaque nouveau produit qu'il existe, qu'il est bon ou qu'il fonctionnera. La plupart des programmeurs pensent que s'ils incorporent chaque nouveau morceau de code publié par une grande entreprise, cela en fait un programmeur plus intelligent; pas vrai du tout. La programmation intelligente consiste principalement à faire plus avec moins de maux de tête, d'incertitudes et en un minimum de temps. Souvenez-vous du temps! C'est l'élément le plus important, alors essayez de trouver des moyens de ne pas le gaspiller en résolvant des problèmes dans un code mauvais / gonflé écrit simplement pour se conformer à certains soi-disant `` modèles '' étranges.
Détendez-vous, profitez de la vie, faites une pause dans le codage et arrêtez d'utiliser des fonctionnalités supplémentaires, du code, des produits, des «modèles». La vie est courte et la durée de vie de votre code est encore plus courte, et ce n'est certainement pas sorcier. Supprimez les couches telles que LINQ, EF et autres, et votre code fonctionnera efficacement, sera mis à l'échelle et, oui, il sera toujours facile à maintenir. Trop d'abstraction est un mauvais «modèle».
Et c'est la solution à votre problème.
la source
Une suggestion consiste à utiliser LINQ to Entity Framework uniquement pour les instructions CRUD à enregistrement unique.
Pour des requêtes, des recherches, des rapports, etc. plus complexes, écrivez une procédure stockée et ajoutez-la au modèle Entity Framework comme décrit sur MSDN .
C'est l'approche que j'ai adoptée avec quelques-uns de mes sites et cela semble être un bon compromis entre productivité et performance. Entity Framework ne génère pas toujours le SQL le plus efficace pour la tâche à accomplir. Et plutôt que de passer le temps à comprendre pourquoi, l'écriture d'une procédure stockée pour les requêtes les plus complexes me fait gagner du temps. Une fois que vous êtes familiarisé avec le processus, il n'est pas trop compliqué d'ajouter des processus stockés à votre modèle EF. Et bien sûr, l'avantage de l'ajouter à votre modèle est que vous obtenez toute cette bonté fortement typée qui vient de l'utilisation d'un ORM.
la source
Si vous êtes récupérez uniquement des données, c'est une grande aide pour les performances lorsque vous dites à EF de ne pas garder une trace des entités qu'il récupère. Pour ce faire, utilisez MergeOption.NoTracking. EF générera simplement la requête, l'exécutera et désérialisera les résultats en objets, mais n'essaiera pas de suivre les modifications d'entité ou quoi que ce soit de cette nature. Si une requête est simple (ne passe pas beaucoup de temps à attendre le retour de la base de données), j'ai constaté que la définir sur NoTracking peut doubler les performances des requêtes.
Consultez cet article MSDN sur l'énumération MergeOption:
Résolution d'identité, gestion de l'état et suivi des modifications
Cela semble être un bon article sur les performances d'EF:
Performance et Entity Framework
la source
Vous dites que vous avez profilé l'application. Avez-vous également profilé l'ORM? Il existe un profileur EF d'Ayende qui mettra en évidence les endroits où vous pouvez optimiser votre code EF. Vous pouvez le trouver ici:
http://efprof.com/
N'oubliez pas que vous pouvez utiliser une approche SQL traditionnelle avec votre ORM si vous avez besoin de gagner en performances.
S'il existe un ORM plus rapide / meilleur? Selon votre modèle d'objet / de données, vous pouvez envisager d'utiliser l'un des micro-ORM, tels que Dapper , Massive ou PetaPoco .
Le site Dapper publie quelques benchmarks comparatifs qui vous donneront une idée de leur comparaison avec d'autres ORM. Mais il convient de noter que les micro-ORM ne prennent pas en charge le riche ensemble de fonctionnalités des ORM complets tels que EF et NH.
Vous voudrez peut-être jeter un oeil à RavenDB . Il s'agit d'une base de données non relationnelle (d'Ayende encore une fois) qui vous permet de stocker des POCO directement sans aucun mappage nécessaire . RavenDB est optimisé pour les lectures et rend la vie des développeurs beaucoup plus facile en supprimant le besoin de manipuler le schéma et de mapper vos objets à ce schéma. Cependant, sachez qu'il s'agit d'une approche très différente de l'utilisation d'une approche ORM et que celles-ci sont décrites sur le site du produit .
la source
J'ai trouvé la réponse de @Slauma ici très utile pour accélérer les choses. J'ai utilisé le même type de modèle pour les insertions et les mises à jour - et les performances ont explosé.
la source
D'après mon expérience, le problème n'est pas avec EF, mais avec l'approche ORM elle-même.
En général, tous les ORM souffrent de problèmes N + 1 , pas de requêtes optimisées, etc.
la source
Il s'agit d'une simple option non-cadre, non ORM qui se charge à 10 000 / seconde avec 30 champs environ. Fonctionnant sur un vieil ordinateur portable, donc probablement plus rapide que cela dans un environnement réel.
https://sourceforge.net/projects/dopersistence/?source=directory
la source
J'ai également rencontré ce problème. Je déteste vider sur EF parce que cela fonctionne si bien, mais c'est juste lent. Dans la plupart des cas, je veux juste trouver un enregistrement ou une mise à jour / une insertion. Même les opérations simples comme celle-ci sont lentes. J'ai récupéré 1100 enregistrements d'une table dans une liste et cette opération a pris 6 secondes avec EF. Pour moi, c'est trop long, même épargner prend trop de temps.
J'ai fini par créer mon propre ORM. J'ai extrait les mêmes 1100 enregistrements d'une base de données et mon ORM a pris 2 secondes, beaucoup plus rapidement que EF. Tout avec mon ORM est presque instantané. La seule limitation pour le moment est qu'il ne fonctionne qu'avec MS SQL Server, mais il pourrait être modifié pour fonctionner avec d'autres comme Oracle. J'utilise MS SQL Server pour tout en ce moment.
Si vous souhaitez essayer mon ORM, voici le lien et le site Web:
https://github.com/jdemeuse1204/OR-M-Data-Entities
Ou si vous souhaitez utiliser nugget:
PM> Install-Package OR-M_DataEntities
La documentation est là aussi
la source
Cela n'a de sens d'optimiser qu'après avoir profilé. Si vous découvrez que l'accès à la base de données est lent, vous pouvez utiliser des procédures stockées et conserver EF. Si vous découvrez que c'est l'EF lui-même qui est lent, vous devrez peut-être passer à un ORM différent ou ne pas utiliser du tout un ORM.
la source
Nous avons une application similaire (Wcf -> EF -> base de données) qui fait 120 requêtes par seconde facilement, donc je suis plus que sûr que EF n'est pas votre problème ici, cela étant dit, j'ai vu des améliorations de performances majeures avec les requêtes compilées.
la source
J'ai utilisé EF, LINQ to SQL et dapper. Dapper est le plus rapide. Exemple: j'avais besoin de 1000 enregistrements principaux avec 4 sous-enregistrements chacun. J'ai utilisé LINQ pour SQL, cela a pris environ 6 secondes. Je suis ensuite passé à dapper, j'ai récupéré 2 jeux d'enregistrements de la procédure stockée unique et pour chaque enregistrement ajouté les sous-enregistrements. Temps total 1 seconde.
De plus, la procédure stockée utilisait des fonctions de valeur de table avec application croisée, j'ai trouvé que les fonctions de valeur scalaire étaient très lentes.
Mon conseil serait d'utiliser EF ou LINQ to SQL et, dans certaines situations, passer à dapper.
la source
Entity Framework ne doit pas causer de goulots d'étranglement majeurs en soi. Il y a de fortes chances qu'il y ait d'autres causes. Vous pouvez essayer de basculer EF vers Linq2SQL, les deux ont des fonctionnalités de comparaison et le code devrait être facile à convertir, mais dans de nombreux cas, Linq2SQL est plus rapide que EF.
la source