2009-11-23 4 views
1

J'ai cette requête qui est exécutée via Linq to Entities. La première fois que la requête s'exécute, elle génère le plan d'exécution qui prend un peu moins de 2 minutes. Une fois le plan mis en cache, la requête prend 1 ou 2 secondes. Le problème que j'ai est que le plan ne cesse de se reconstruire toutes les quelques heures et je ne suis pas sûr de savoir pourquoi.Reconstruction du plan d'exécution de requête SQL Server

Ceci est la requête linq que nous utilisons, je sais que cela semble fou, mais pour ce dont nous avons besoin c'était notre seule option.

var data = from row in mgr.ServiceDesk_RequestEvent 
    .Include("ServiceDesk_Event") 
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule") 
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet") 
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Rule") 
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Rule.ServiceDesk_RuleOperator") 
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Rule.ServiceDesk_RuleConstraintField") 
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Rule.ServiceDesk_RuleConstraintValue") 
    .Include("ServiceDesk_Event.ServiceDesk_SLAEventRule.ServiceDesk_RuleSet.ServiceDesk_Action") 
    .Include("ServiceDesk_Request") 
    .Include("ServiceDesk_Request.People_User") 
    .Include("ServiceDesk_Request.ServiceDesk_RequestCategory") 
    .Include("ServiceDesk_Request.ServiceDesk_RequestCategory.ServiceDesk_SLA") 
    .Include("ServiceDesk_Request.ServiceDesk_RequestRole_Groups") 
    .Include("ServiceDesk_Request.ServiceDesk_RequestRole_Groups.Security_Role.Security_UserRoles") 
    .Include("ServiceDesk_Request.ServiceDesk_RequestRole_Groups.Security_Role.Security_UserRoles.Security_User") 
    .Include("ServiceDesk_Request.ServiceDesk_RequestPriority") 
    .Include("ServiceDesk_Request.Offices_User") 
    .Include("ServiceDesk_Request.ServiceDesk_RequestTechnicians") 
    .Include("ServiceDesk_Request.ServiceDesk_RequestTechnicians.People") 
    where row.Completed == false && row.Deleted == false 
    select row; 

Je ne veux pas coller le t-sql généré ici car il est assez grand. Si quelqu'un a des idées, n'hésitez pas à contribuer.

Merci.

+0

Vous avez raison. Ça a l'air fou. Vous avez réellement besoin de tous les champs de chaque entité que vous incluez * et * vous avez l'intention de mettre à jour chaque instance * et * vous avez profilé et constaté que c'est plus rapide que le chargement individuel de la demande? C'est le seul argument raisonnable que je peux penser pour faire cela au lieu de projeter (mon premier choix pour les cas d'utilisation en lecture seule) ou de se lancer dans de plus petites requêtes. –

Répondre

1

Une cause possible est que votre serveur soit sous la pression de la mémoire, ce qui entraîne une récupération plus rapide du cache du plan de requête.

De combien de RAM dispose le serveur?

Relisant votre question, cette ligne est un peu inquiétante: "La première exécution de la requête génère le plan d'exécution qui prend un peu moins de 2 minutes". 2 minutes la première fois pour une requête simple est longue. Exécutez-vous d'autres applications sur la boîte SQL Server (heureusement non)?

Je vous suggère de surveiller avec les compteurs de performance intégrés: SQL Server, Plan Cache Counters.

Suppression des plans d'exécution de la procédure Cache

plans d'exécution restent dans le cache de procédure tant car il y a suffisamment de mémoire pour stocker les . Lorsque la pression de mémoire existe, le moteur de base de données utilise une approche basée sur les coûts pour déterminer quelle exécution prévoit de supprimer de la procédure le cache. Pour prendre une décision fondée sur les coûts, la base de données du moteur augmente et diminue une variable de coût actuel pour chaque plan d'exécution en fonction des facteurs suivants .

Lorsqu'un processus utilisateur insère un plan d'exécution dans le cache, le processus utilisateur définit le coût actuel égal à la compilation coût requête initiale; Pour les plans d'exécution ad-hoc, le processus utilisateur définit le coût actuel sur zéro. Par la suite, chaque fois qu'un processus utilisateur référence un plan d'exécution, il réinitialise le coût actuel au coût de compilation original ; pour les plans d'exécution ad hoc , le processus utilisateur augmente le coût actuel. Pour tous les plans , la valeur maximale pour le coût actuel est le coût original de compilation .

Lorsque la pression de mémoire existe, le moteur de base de données répond en supprimant plans d'exécution de la procédure cache. Pour déterminer qui prévoit de supprimer , le moteur de base de données à plusieurs reprises examine l'état de chaque exécution un plan et supprime les plans lorsque leur coût actuel est égal à zéro.Un plan d'exécution avec coût actuel nul n'est pas supprimé automatiquement lorsque la mémoire existe; il est supprimé uniquement lorsque le moteur de base de données examine le plan et que le coût actuel est égal à zéro. Lors de l'examen d'un plan d'exécution, le moteur de base de données pousse le coût actuel vers zéro en diminuant le coût actuel si une requête n'est pas en cours d'utilisation du plan. Le moteur de base de données examine à plusieurs reprises les plans d'exécution jusqu'à ce que ait été supprimé pour satisfaire aux exigences de mémoire . Alors qu'il existe une pression de mémoire , un plan d'exécution peut avoir son coût augmenté et diminué plus d'une fois. Lorsque la pression de mémoire n'existe plus, le moteur de base de données cesse de diminuer le coût actuel des plans d'exécution inutilisés et tous les plans d'exécution restent dans le cache de procédure , même si leur coût est zéro.

Le moteur de base de données utilise la ressource threads moniteur et l'utilisateur pour libérer mémoire du cache de procédure réponse à la pression de la mémoire. Le moniteur de ressources et les threads utilisateur peuvent examiner les plans exécutés simultanément à diminuer le coût actuel pour chaque plan d'exécution inutilisé . Le moniteur de ressource supprime les plans d'exécution de le cache de procédure lorsque la mémoire globale existe. Il libère de la mémoire pour appliquer des stratégies pour la mémoire système, mémoire de processus, mémoire de pool de ressources, et la taille maximale pour tous les caches.

La taille maximale pour tous les caches est une fonction de la taille du pool de mémoire tampon et ne doivent pas dépasser le serveur maximale mémoire. Pour plus d'informations sur en configurant la mémoire maximale du serveur, , reportez-vous au paramètre de mémoire maximale du serveur dans sp_configure (Transact-SQL).

Si vous ne l'avez pas déjà vu: Plan Caching in SQL Server 2008

+0

Le serveur dispose de 8 Go de RAM mais il n'est pas sous forte charge. Mais s'il y a un moyen de confirmer que ce serait génial. – Lukasz

1

This MSDN article est une bonne référence sur le cache de plan d'exécution. Une façon d'optimiser l'utilisation du plan d'exécution consiste à utiliser du SQL paramétré au lieu du SQL codé en dur/dynamique.

par exemple.

SELECT * FROM MyTable WHERE [email protected] 

est mieux que

SELECT * FROM MyTable WHERE ID=1 

comme peut être mis en mémoire cache du même plan et réutilisé, peu importe quelle est la valeur de @Id. Plus un plan d'exécution est réutilisé, plus il est probable qu'il reste dans le cache car il est jugé utile.

Je ne connais pas le type d'instruction que LINQ crée, mais cela vaut la peine d'en tenir compte. Aussi, comme l'a dit Mitch, plus vous avez de mémoire, plus vous pouvez stocker dans le cache. Notez également que ce n'est pas seulement la mise en cache du plan d'exécution qui est à l'œuvre ici.Vous avez également le cache de données qui a une énorme différence sur les performances - une fois que vous avez exécuté la requête une fois, les données seront conservées dans le cache de données, donc pour les appels ultérieurs les données sont déjà en mémoire - c'est la source de la différence de performance.

+0

LINQ to Entities génère un sql paramétré donc je ne pense pas que ce soit le problème. Merci pour l'article! – Lukasz

+0

ah ok. Juste noter ma dernière édition à propos de cache de données aussi - c'est un biggy pour la performance – AdaTheDev