Bonjour à tous,
J'ai rédigé ce petit papier pour bousculer, un peu, les certitudes au sujet des ORM et de leurs performances: http://immobilis.developpez.com/tuto...ity-framework/
N'hésitez pas à me dire ce que vous en pensez :ccool:
A+
Version imprimable
Bonjour à tous,
J'ai rédigé ce petit papier pour bousculer, un peu, les certitudes au sujet des ORM et de leurs performances: http://immobilis.developpez.com/tuto...ity-framework/
N'hésitez pas à me dire ce que vous en pensez :ccool:
A+
Salut,
J'y ai jeté un coup d'oeil vite fait !
Le sujet abordé est intéressant et l'article très bien écrit.
J'ai mis l'article dans ma liste de tutos en attente.
A première vue, j'ai l'impression que tu t'es trop acharné sur l'architecture de ton application alors qu'il s'agit juste de tester et comparer les performance de requêtes (SQL, Ling To SQL et Linq To Entities).
Excellent article, très intéressant, pour faire des choix et connaitre les différences.
L'introduction, quoi qu'un peu longue, sur ton archi, amène bien le découpage et les besoins.
A noter également, avec une bonne abstraction on peut passer de l'un à l'autre sans (trop) de mal.
Comme je te l'ai déjà dit dans un autre poste, très bon article.
Par contre à la deuxième lecture quelque chose me surprend :
L'utilisation de Linq to Entities avec des SP est plus performantes que Linq to Entities et très proche des performances de SQL(Command)...
Cela me surprend d'autant que j'ai eu les résultats très différent en faisant un benchmark sur mon application au boulot.
Pour info j'avais un programme qui en gros, supprimait 100 lignes, en rajoutait 100, et faisais ça sur environ 1 million de lignes en tout.
Les résultats que j'ai obtenu, c'est que LinqToEntitesSP donne quasiment les même performances que LinqToEntites, alors que SQL(Command) était 9 fois plus rapide.
Du coup je me pose la question de savoir s'il y a une différence de performance entre :
etCode:db.Customers.AddObject(c);
Code:db.AddToCustomers(c);
Et si par hasard on n'a pas, toi comme moi, des mauvaises optimisations au niveau du code...
Cette discussion promet d'être enrichissante :)
Je regarde surtout le tableau récapitulatif. Sur mon portable Linq+Cmd effectue deux cycles complets le plus rapidement. C'est très serré avec EntitiesSqlSP. Ensuite il faut regarder le détail des opérations.
Quand on regarde les requêtes générée par le fournisseur EntitiesCustomerProvider:et EntitiesSqlSPCustomerProvider:Code:exec sp_executesql N'insert [dbo].[Customers]([Id], [LastName], [FirstName]) values (@0, @1, @2) ',N'@0 uniqueidentifier,@1 varchar(50),@2 varchar(50)',@0='63716843-0523-43DB-814D-720F0EA89D55', @1='7pL7ob8pmrWDC0k',@2='7pL7ob8pmrWDC0krI0a5'
J'ai du mal à imaginer que EntitiesCustomerProvider est plus rapide. D'ailleurs, il arrive bon avant dernier dans le tableau.Code:exec [dbo].[CreateCustomer] @Id='E70A41CC-CC1C-4328-B24C-DA02038B6929', @LastName='lpPdOXNPPov8Qg5',@FirstName='lpPdOXNPPov8Qg5MLDVy'
Si db.AddToCustomers(c) est bien l'appel à une procédure stockée, pour moi c'est clair. L'utilisation de procédures stockées rend le code plus rapide. Il suffit de regarder les deux graphiques pour s'en convaincre. Les échelles de temps sont les mêmes, 3mn
Sans procédure stockée:
Avec procédure stockée:
Non justement ce n'est pas une procédure stockée, c'est une méthode générée par EF.
Les procédures stockées ne sont pas "plus rapides" avec SQL Server 2008 R2 à ma connaissance, sauf si tu as poussé le vice jusqu'à optimiser le plan d'éxecution, et encore... Et c'est pour ça que ça me surprend.
Le bon dernier c'est Linq et ça ne m'étonne pas, ce qui me surprend, c'est que Linq to Entites avec SP soit bien plus performant que Linq to Entities tout court, et qu'il ait des performances proche de SQL Command.
Après ça peut venir du jeu de test...
Je suis pas très bon en ça... :PCitation:
sauf si tu as poussé le vice jusqu'à optimiser le plan d'éxecution
En premier les méthodes natives, en deuxième les méthodes avec les proc stock.Je doutes que la différence change quelque soit l'environnement.
Création, Entity seul:
Contre Entity + PSCode:exec sp_executesql N'insert [dbo].[Customers]([Id], [LastName], [FirstName]) values (@0, @1, @2)',N'@0 uniqueidentifier,@1 varchar(50),@2 varchar(50)',@0='DAF9D021-F60E-47EE-881C-851DFF8F8EEA',@1='dMtAktsNSeobzEY',@2='dMtAktsNSeobzEYsK58x'
Suppression, Entity seul:Code:exec [dbo].[CreateCustomer] @Id='12503D00-B5C2-40CD-B0A2-FCBC96ECC72A',@LastName='q0SuytswT6DYuOM',@FirstName='q0SuytswT6DYuOM3s2NJ'
Contre Entity + SPCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 exec sp_executesql N'SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[LastName] AS [LastName], [Extent1].[FirstName] AS [FirstName] FROM [dbo].[Customers] AS [Extent1] WHERE [Extent1].[Id] = @p__linq__0',N'@p__linq__0 uniqueidentifier',@p__linq__0='77863927-C8C4-4090-A80F-2D8C2BF94810' go exec sp_reset_connection go exec sp_executesql N'delete [dbo].[Customers] where ([Id] = @0)',N'@0 uniqueidentifier',@0='77863927-C8C4-4090-A80F-2D8C2BF94810' go exec sp_reset_connection go
Y'a pas photo.Code:
1
2
3
4 exec [dbo].[DeleteCustomer] @ID='79AE9A99-ED2C-4567-85F4-06DD7FCED110' go exec sp_reset_connection go
Je vais essayer de prendre le temps ce week end de faire le test, entre EF avec SP, EF sans SP et SQL Command brut, parce que les différences que tu montres me surprennes.
Je n'ai pas suivi tout ton code, mais quand tu fais des insert de masse, tu passes des collections à tes méthodes, ou tu passes individuellement chaque objet ? C'est peut-être ce qui fait la différence entre nos benchmark !
Faudrait que SQLPro participe à cette discussion. Il pourrait y apporter une grosse valeur ajoutée, je pense.
Sinon, pour l'article, un conseil : évite le code centré. C'est assez illisible.
Ah ben voilà la diff alors, je passe par un bulkinsert... Là tu vois la différence, vraiment.
(ça tombe bien j'avais pas envie de coder avec le temps qu'il fait...)
C'est dommage qu'on ne puisse pas de la même façon optimiser les méthodes EF.
Parce que ce qui cause une perte de temps c'est la recherche de l'ID systématique, notamment pour l'insert et le delete.
Tu récupères les requêtes générées via SQL Profiler ?
Ceci est recolté via le SQL PROFILER... CreateCustomer est donc bien une SP présente sur le server SQL...Citation:
exec [dbo].[CreateCustomer] @Id='E70A41CC-CC1C-4328-B24C-DA02038B6929', @LastName='lpPdOXNPPov8Qg5',@FirstName='lpPdOXNPPov8Qg5MLDVy'
->Immobilis: que te retournes celà:
Code:
1
2
3
4 SELECT * FROM [taDataBase].sys.PROCEDURES WHERE NAME='CreateCustomer'
CeciCitation:
name.......................................CreateCustomer
object_id..................................37575172
principal_id................................NULL
schema_id................................1
parent_object_id........................0
type.........................................P
type_desc.................................SQL_STORED_PROCEDURE
create_date...............................2011-06-25 00:20:33.653
modify_date...............................2011-06-25 13:03:57.620
is_ms_shipped............................0
is_published...............................0
is_schema_published...................0
is_auto_executed.......................0
is_execution_replicated................0
is_repl_serializable_only................0
skips_repl_constraints..................0
C'est EF qui a crée lui même cette SP?
Si oui bon les règles de nommage! je rêve! :ccool:
Non non, c'est moi pourquoi? J'ai enfreint une règle de nommage?
Beaucoups vont dire que c'est subjectif mais oui... tout en majuscule avec undescore, SP_ en prefixe des SP...Citation:
Non non, c'est moi pourquoi? J'ai enfreint une règle de nommage?
http://sqlpro.developpez.com/cours/standards/
Et bien je ne suis pas daccord avec lui...
MICROSOFT, pour toucher les développeurs, tente d'instaurer le CAMEL CASE, et pourquoi?
Simple... c'est bien pratique quand on génère l'EDMX puisque celui-ci garde par défaut le nom des tables du coups "c'est pas bo ces classes en MAJUSCULE"... c'est tout...
De toute manière MICROSOFT n'a JAMAIS respecté les normes de nommage quand il s'agit d'intéragir avec .NET...
Bien avant LINQ, il fallait voir les SP et tables générées pour la gestion utilisateur/membership/profile/role intégrée ASP.NET!
Avec NVARCHAR et GUID au taquet en plus(sans débattre sur l'utilisation du GUID bien sûr :-))
+1 pour les GUID.
C'est pas tant l'utilisation de CamelCase dans les procédures stockées qui me gêne, c'est plus dans les index, keys, attributs de table, etc...
:mouarf::mouarf: Grand troll en perspective.
Bon, pour info, en l’occurrence on parle aussi de PascalCase. Je suis pas trop à cheval là dessus. Perso, en fait, je "PascalCase" (Microsoft) tandis que d'autres "camelCase":
A vous de voir si vous préférez
- http://blogs.msdn.com/b/brada/archiv.../03/67024.aspx
- http://msdn.microsoft.com/en-us/libr...40(VS.80).aspx
ouCode:db.SP_CREATE_CUSTOMER(obj.Id, obj.LastName, obj.FirstName);
dans votre code.Code:db.CreateCustomer(obj.Id, obj.LastName, obj.FirstName);
A+
????Citation:
Grand troll en perspective.
OK... une des origines de cette convention est que :
- Certaines bases de données son en collation CS ou BINAIRE... d'ou l'utilité d'utiliser les MAJUSCULES...
- Celà limite l'écriture par des développeurs (ou DBA peu consciencieux...) de requètes avec des CASSES différentes, ce qui maximise l'utilisation du cache, en effet sachez que si vous faites
etCode:SELECT NOM FROM MATABLE
et bien vous forcez SQL SERVER à générer deux plans d'executions et à les mettre deux fois en cache...Code:SELECT NOM FROM matable
Encore une fois je ne vois pas en quoi le fait de renommer votre SP dans votre DBML est compliqué si c'est ca qui vous gène???Citation:
A vous de voir si vous préférez
db.SP_CREATE_CUSTOMER(obj.Id, obj.LastName, obj.FirstName);
ou
db.CreateCustomer(obj.Id, obj.LastName, obj.FirstName);dans votre code.
A+
C'est que parfois dans mon boulot cela a donné lieu à des disputes mémorables :mouarf:
Intéressant, je n'y avais jamais songé. Faut vraiment être DBA pour penser à tout ça!
Sinon, j'imagine que produire un tel document de convention est/était nécessaire parce qu'il n'y n'avait pas d'intellisens. Du coup, en mettant tout le monde en majuscules c'est plus pratique. Par contre, sachant que le renommage n'est pas aussi simple que sous Visual Studio, utilisez tout ces préfixes est un travail de dingue!
Je n'ai pas vu la possibilité d'ajouter des alias...
+1
Autre doc: http://msdn.microsoft.com/en-us/libr...72(VS.71).aspx
Très intéressant! http://msdn.microsoft.com/fr-fr/netf.../hh237550.aspx
Et pour info, Iberserk me corrigera si je me trompe, mais il me semble que le préfixe "SP" pour les procédures stockées devrait être réservé à la seule utilisation de Microsoft dans SQL Server. Les procédures stockées applicatives doivent être nommée différemment, par exempleCode:db.SP_CREATE_CUSTOMER(obj.Id, obj.LastName, obj.FirstName);
Code:db.CODE_APPLI_CREATE_CUSTOMER(obj.Id, obj.LastName, obj.FirstName);
Nathanael :
Oui tout à fait...Citation:
J'ai bon?
rien ne vous empeche de garder les conventions de nommage CHARP dans votre EDMX.... y compris pour les procédures stockées et fonctions tables (ne les oublions pas...).Citation:
Et pour info, Iberserk me corrigera si je me trompe, mais il me semble que le préfixe "SP" pour les procédures stockées devrait être réservé à la seule utilisation de Microsoft dans SQL Server. Les procédures stockées applicatives doivent être nommée différemment, par exemple
Je vois que ça se discute pas mal.
Pour ma part je n'ai pas encore eu le temps ce week end pour me plonger dans le tuto.
Sinon pour ceux qui n'avaient pas assisté à l'après-midi du développement sur Entity Framework chez Microsoft je vous conseille de visionner le webcast ici.
ça parle de tout et même de l'optimisation des requêtes Linq To Entities dans la partie 9 du webcast et cette partie pourra intéresser plus d'un et c'est vraiement très instructif vu que la plupart du temps on se lance dans EF sans comprendre ce qui passe derrière.
Merci docteur:D
Je vais aller voir ca, je n'ai pas vu cette webcast.
Excellentes analyse 'pas besoin d'être un expert SQL pour savoir qu'ici il vaut mieu utiliser l'include: il génère 200000 requêtes sans'
Pardon:?
Bonjour à tous !
L'article est trés trés interressant mais j'ai 2 ou 3 petites questions.
Au debut de la sortie de EF, j'ai voulu l'utilisé mais j'ai toujours trouvé des différences de performances par rapport à l'utilisation des Dataset ou des objets ADO.Net (SqlCommand ...). Les temps de chargement pour des petites tables était trés important, bien sur je ne connaissais pas cette techno et je me rend compte aujourd'hui qu'il existe de nombreuses possibilités d'optimisation. L'une d'elle est l'utilisation de procédures stockées, mais quand on a une base d'environ 50 tables, c'est fait tout de meme pas moins de 200 PS qu'il faut créer !!!
Mes questions :
- Utilisez vous des PS (CRUD) pour chaque table ou bien attaquez vous directement les tables ?
- Quelles sont vos optimisations sous EF ?
Salut,
Merci pour ton accueil de cet article :)
Il existe des générateurs de PS pour les opérations du CRUD.
Dans la mesure du possible, au regard des résultats, dans tous les cas, il vaut mieux faire des PS dès que c'est possible. C'est effectivement du travail. Cela peut donner des procédures comme: GetUsersByName, GetUserById, GetUsersByTown, etc. Tu peux aussi imaginer faire un UsersSelectAll au démarrage de l'application, mettre les données en cache et faire la recherche par le code. Tu gardes ainsi le jeu de données sur le serveur web et tu ne requêtes plus la base.
Si on retourne la question: dans quels cas une procédure stockée répond moins bien au besoin? Je dirais toutes les fois où la liste des champs ainsi que les clauses de la requête sont construites par le code. Ces cas là sont assez rares. Cela arrive dans le cas de moteur de recherche je dirais.
Finalement, j'utilise assez peu EF :P Les PS sont une bonne optimisation. Je te suggère de regarder le web cast deuxième lien dans les références: http://immobilis.developpez.com/tuto...amework/#LVIII. On peut en retenir une chose essentielle: ne demander à la base de données que ce dont on a réellement besoin.
A+