Accueil > .Net, C#, Développement > [C# EF5] Requêtes Compilées

[C# EF5] Requêtes Compilées

Ce billet fait suite à la petite série sur l’optimisation.
La situation est expliquée ici Optimisations C#, Entity Framework et Sql, donc je n’y reviendrais pas.

Ce billet va traiter d’une optimisation au niveau de LINQ : les requêtes compilées.

Le scénario :
J’ai une liste de N éléments, peut être 1, mais dans mon test de charge : 50.000.
Chaque élément est un objet contenant une agrégation logique des plusieurs autres objets que je peuple au fil des traitements.
Je dois peupler l’un d’eux à partir d’une table très grosse (la même table qu’avant, avec ces 75 millions d’entrées).

 

Les solutions envisagées

 
Je récupère tous mes identifiants d’un côté pour faire un WHERE IN massif.
Problème 1 : la clause WHERE IN contient 50.000 identifiants.
Problème 2 : comment réconcilier ma liste d’entrées obtenue avec ma liste d’objets à alimenter ?

Je récupère tous mes identifiants et vais chercher les données par lot.
Problème 1 : combien de lignes par lot ? 10% ? 20% ?
Problème 2 : comment réconcilier mes listes d’entrées obtenues avec ma liste d’objets à alimenter ?

Je boucle par paquet des X lignes.
Problème 1 : c’est long, je vais avoir 2 boucles en tout (la 1ère pour les lots, la 2ème pour les éléments du lot)

J’utilise une procédure stockée pour tout gérer.
Problème 1 : c’est ce qu’on avait avant. C’est pas facilement maintenable.
Problème 2 : comment réconcilier ma liste d’entrées obtenue avec ma liste d’objets à alimenter ? Avant, on se trimbalait plusieurs listes et on devait vérifier que l’index 1 dans la liste A correspond bien à l’index 1 dans les listes B et C…

Aucune solution n’est satisfaisante…
EF n’aime que moyennement que l’on remonte des lignes en masse, donc ça exclut de traiter le tout en une seule fois.
Ensuite, quand je tente de réconcilier les listes, LINQ m’envoie bouler parce que la requête est trop lourde/prend trop de temps (vers à peut près 20.000 lignes).

 

Solution retenue

 
C’est du ligne par ligne qui a été adopté.
C’est moche, mais ça à le mérite de parfaitement remplir son office.
Et à ma plus grande surprise, la base de données semble préférer (elle est plus paisible que sur les solutions précédentes), pour peu que je reste sur la même connexion (faut quand même pas déconner…).
Mais pour optimiser un peu plus et comme je n’ai besoin que de l’information en lecture, je spécifie le MergeOption à NoTracking, sur le context. Ça permet de ne pas utiliser l’ObjectStateManager et donc de gagner encore un peu.

Mais du coup, faire tourner une boucle sur 50.000 lignes, avec une requête LINQ/EF de base, ça donne : 43 millisecondes la première fois, puis 10 les suivantes.
Donc, on obtient environ 500.000 millisecondes, soit 500 secondes, soit 8 minutes environ.
Pas terrible. Vraiment pas…

 

Compiled Queries

 

Et là, l’illumination grâce à Internet, du moins grâce à ce billet en particulier Performance Considerations for Entity Framework 5
Je vous conseille TRÈS fortement de le lire et surtout de le garder sous le coude, c’est une vraie mine d’or.

Il faut donc se reporter à la section « 3.3 Using CompiledQuery to improve performance with LINQ queries » pour comprendre ce que sont les CompiledQuery.
Comme c’est plutôt bien expliqué et somme toute assez simple à prendre en main, je ne vais pas poster de code ici.

Par contre, je vais donner le gain de temps : 57 millisecondes (+14) la première fois, puis 2 (-6) les suivantes.
Ça n’a pas l’air énorme, comme ça, mais ça donne : 100.055 millisecondes, soit 100 secondes, soit 1.5 minutes.

Autrement dit, on perd un peu sur la première itération, mais dès la troisième, on est gagnant !

 

Compléments

 

Compiled Queries (LINQ to Entities).
When should I use a CompiledQuery?

Catégories :.Net, C#, Développement
  1. Aucun commentaire pour l’instant.
  1. 05/02/2014 à 22:43
  2. 10/02/2014 à 12:24

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :