8
votes

Comment réduire l'entité Framework 4 Demande de compilation de la requête?

Résumé: Nous avons des problèmes avec des temps de compilation des requêtes EF4 de 12+ secondes. les requêtes mises en cache ne nous obtenir jusqu'à présent; ce qu'il ya des façons dont nous pouvons effectivement réduire le temps de compilation? Y at-il que nous pourrions faire mal, nous pouvons chercher? Merci!

Nous avons un modèle EF4 qui est exposé sur les services WCF. Car nous exposons chacun de nos types d'entités une méthode pour récupérer et retourner l'entité entière pour l'affichage / édition, y compris un certain nombre d'objets enfants référencés.

Pour une entité particulière que nous avons à .include () 31 tableaux / sous-tables de retourner toutes les données pertinentes. Malheureusement, ce qui rend la compilation des requêtes EF extrêmement lents: il faut 12-15 secondes pour compiler et construit une ligne 7800, requête 300K. Ceci est l'arrière-plan d'une interface Web qui devra être souplement que cela.

Y at-il quelque chose que nous pouvons faire pour améliorer cela? Nous pouvons CompiledQuery.Compile cela - qui ne fait pas de travail avant la première utilisation et aide ainsi les exécutions deuxième et suivantes, mais notre client est nerveux que la première utilisation ne doit pas être lent non plus. De même, si le pool d'application IIS qui héberge le service Web est recyclé, nous allons perdre le plan mis en cache, même si nous pouvons augmenter la durée de vie pour minimiser cela. Je ne peux pas voir un moyen de précompiler cette avance et / ou serialise le cache de requête EF compilé (à court de tours de réflexion). L'objet CompiledQuery ne contient qu'une référence GUID dans le cache de sorte qu'il est le cache nous soucions vraiment. (Rédaction ceci il me semble que je peux lancer quelque chose dans l'arrière-plan de app_startup pour exécuter toutes les requêtes pour les obtenir compilés - est que la sécurité)

Cependant, même si nous résoudre ce problème, nous construisons nos requêtes de recherche de façon dynamique avec des clauses LINQ-à-entités en fonction des paramètres que nous sommes à la recherche sur: Je ne pense pas que le générateur SQL fait un bon travail assez que nous pouvons passer toute cette logique dans la couche SQL, donc je ne pense pas que nous pouvons précompiler nos requêtes de recherche. Ceci est moins grave parce que les résultats des données de recherche utilisent moins de tables et il est donc seulement 3-4 secondes compilent pas 12-15 mais le client pense que encore ne sera pas vraiment acceptable pour les utilisateurs finaux.

Nous avons donc vraiment besoin de réduire le temps de compilation de la requête en quelque sorte. Toutes les idées?

  • Le profilage des points à ELinqQueryState.GetExecutionPlan comme point de départ et j'ai essayé de pas dans cela, mais sans réel disponible I source de .NET 4 ne pouvait pas aller très loin, et la source générée par réflecteur ne me laisse pas pas dans certaines fonctions ou ensemble des points d'arrêt en eux.
  • Le projet a été mis à jour de .NET 3.5, donc j'ai essayé régénérer le EDMX à partir de zéro en EF4 dans le cas où il y avait quelque chose de mal avec elle, mais cela n'a pas aidé.
  • J'ai essayé l'utilitaire EFProf annoncé ici, mais il ne ressemble pas à cela aiderait à cela. Ma grande requête bloque ses Collecteur de données de toute façon.
  • J'ai exécuter la requête générée par l'accord SQL performance et il a déjà 100% l'utilisation des index. Je ne vois rien de mal à la base de données qui causerait des problèmes de générateur de requêtes.
  • Y at-il quelque chose O (n ^ 2) dans le compilateur plan d'exécution - est briser ce en blocs de charges de données séparées plutôt que les 32 tables à la fois susceptibles d'aider? Réglage EF à charge paresseux n'a pas aidé.
  • Je l'ai acheté la préversion O'Reilly Julie Lerman EF4 livre, mais je ne trouve rien là-dedans à l'aide au-delà de « compiler vos requêtes ».

    Je ne comprends pas pourquoi il prend 12-15 secondes pour générer une sélection unique dans 32 tables, donc je suis optimiste, il y a une certaine marge d'amélioration!

    Merci pour toutes suggestions! Nous sommes en cours d'exécution sur SQL Server 2008 dans le cas où les questions et XP / 7 / Server 2008 R2 RTM en utilisant VS2010.


3 commentaires

Nous avons également ce problème, et c'est un problème majeur. Le temps d'exécuter des requêtes est au plus 2-300 ms, en attendant que ElinqQueryState.getexecueCueLan () prend 8-9 secondes. Et c'est après avoir fractionné nos grandes requêtes de charge impatientes que EF ne peut pas gérer (l'habitude de prendre 2 à 4 minutes pour attendre l'ElinqQuystate.getexecueRanplan (), pour chaque QRY) dans de nombreuses requêtes de charge impatiente simples. Je suppose que tout ce que nous pouvons faire est d'attendre EF5 qui est censé soulager une certaine douleur causée par cela.


J'ai posté sur MSDN.Forums sur cette question dans l'espoir d'obtenir des conseils à ce sujet, enfilez ici SOCIAL.MSDN.MICROSOFT.CORUMS/EN-US/ADODOTNETTELITYFRAREW Ork / ...


@ Mahol25 merci - je vais regarder ce fil. Je suis désolé de dire que nous n'avons jamais eu nos questions à moins d'une seconde avant de quitter le projet, donc je n'ai aucune suggestion concrète pour vous donner au-delà de ce qui est déjà ici.


5 Réponses :


1
votes

Ce n'est probablement pas la réponse que vous recherchez, mais pour une solution de contournement simple, pourquoi n'exécutez pas la compiledquery.comPile au moment de l'initialisation de WebApp (faisez-vous un appel factice vers le WebApp) au lieu du premier ( Client) Appelez.


2 commentaires

Merci. Oui, cela vaut la peine d'être essayé à condition que je puisse le faire en arrière-plan - je ne veux pas enfermer le site pendant quelques minutes de compiler toutes les questions à chaque fois que la piscine des applications redémarre. Cependant, cela ne vous aidera pas à accélérer nos requêtes de recherche que nous construisons à la volée et que vous ne pouvez donc pas mettre en cache aussi loin que je peux voir. (L'appel compiléquery.comPILE vient de rassembler la requête avec un Cache GUD et retourne immédiatement - ce n'est qu'à première exécution que la compilée se produit réellement. Donc, je devrais faire une récupération factice sur chaque requête compilée au démarrage à la gâchette. compilation.)


Nous avons mis en place cela comme un fil de fond sur l'application init et il ne semble pas toujours fonctionner malheureusement; Cela fonctionne bien dans un boîtier à un seul thread et il n'y a pas de dépendance du thread dans le code de cache EF4, donc je suis à une perte de la raison pour laquelle cela ne fonctionne pas toujours. Cependant, cela aide dans certains cas donc nous l'avons frappé. Merci pour la suggestion!



8
votes

Faites de vos questions plus simples. Sérieusement; Il y a une relation presque linéaire entre la complexité de la requête et la compilation de temps. Deux requêtes simples sont souvent beaucoup plus rapides qu'une requête vraiment compliquée (même si précompilée!). Si la vitesse est l'objectif final, choisissez l'option la plus rapide.


6 commentaires

Merci, et désolé d'avoir pris des âges de revenir à cela. Oui, c'est ce que nous avons fini par faire plus ou moins pour les cas lis-à-affichage: rompre des charges d'objet dans plusieurs petits morceaux avec des requêtes précompilées pour chacun puis recombinant les données récupérées dans les objets POCO que nous utilisions pour Transport de données. Pour la sécurité, nous avons collaboré à une seule question de grandes requêtes pour les cas de mise à jour en lecture plutôt que d'essayer de recenser les données EF de retour pour l'objet de résultat combiné.


NIT-PICK: La relation linéaire voudrait signifier que le fractionnement ne donnerait aucun avantage et pourrait le nuire en raison d'une constante de permanence supérieure.


@ Merlynmorgan-Graham, l'objectif est de choisir une paire (ou plus) de requêtes plus simples mais équivalentes, sans simplement diviser la complication en deux.


@CRAIGSTUNTZ: Alors cela pourrait avoir un sens.


Cette suggestion tant que de bons conseils généraux sont très naïfs et ne travailleront que dans des modèles de données simplistes. Nous avons profilé la merde hors de cela et nous avons fragé nos requêtes de nombreuses manières différentes, mais cela n'est pas suffisant pour nous (WWE utilise un héritage très limité pour les entités persistantes). ElinqQueryState.getexecueCueLan est juste terrible. Exemple: Querifier un graphique d'objet a commencé à prendre 159 s (toutes les compilations EF), le divisant dans plusieurs QRS produites de la durée de requête de 8,5 S (toutes les complications EF). Ce nombre est toujours complètement inacceptable (cible moins d'une seconde).


@ Mahol25 Votre échec ne rend pas le conseil incorrect. Vous pouvez blâmer vos outils ou me blâmer, mais vous ne pouvez pas conclure que j'ai un "modèle de données simpliste" simplement parce que vous obtenez plus de 8 secondes requêtes. C'est juste idiot.



4
votes

Vous pouvez créer une vue pour certaines de vos requêtes plus complexes qui vous donne le contrôle complet du SQL. Ensuite, incluez cette vue dans votre modèle de données.


1 commentaires

Merci, et désolé d'avoir pris des âges de revenir à cela. Oui, nous avons fini par créer des vues pour certaines des requêtes en lecture seule (résultats de recherche, etc.), mais nous sommes restés coincés pour construire des arbres d'objets pour des extratures d'objet générales.



1
votes

Vous pouvez essayer d'utiliser http://www.iis.net/download/applicationwarmup C'est en bêta maintenant, mais nous tenons à l'utiliser aussi.


1 commentaires

Merci pour la suggestion et désolé d'avoir pris des âges de revenir à cela. Les pouvoirs - on veut dire non, du moins pas tandis que c'est encore une bêta, nous avons donc fini par faire quelque chose de similaire dans un fil de fond - malheureusement avec succès limité: - /



1
votes

Jetez un coup d'œil à Nqueries , il utilise des requêtes précompilées, générées lors du démarrage de l'application.

EDIT: Depuis le passage à EF5, les nqueries ne supportent plus les requêtes compilées lorsqu'elles sont passées à DBContext, si vous souhaitez toujours jeter un coup d'œil, prenez le Code source de version 1.03 , qui est toujours à base d'objetContext basé et prend en charge les requêtes compilées.


1 commentaires

Merci. Je vais jeter un coup d'œil, mais nous produisons déjà des compiléqueries et utilisons des vues précompilées aussi loin que possible - je ne vois pas ce qu'il peut faire d'autre au démarrage.