2010-02-22 3 views
10

J'ai une requête LINQ to SQL qui génère l'instruction SQL suivante:'plan de requête LINQ' horriblement inefficace mais 'plan de requête Query Analyzer' est parfait pour le même SQL!

exec sp_executesql N'SELECT COUNT(*) AS [value] 
FROM [dbo].[SessionVisit] AS [t0] 
WHERE ([t0].[VisitedStore] = @p0) AND (NOT ([t0].[Bot] = 1)) AND 
([t0].[SessionDate] > @p1)',N'@p0 int,@p1 datetime', 
@p0=1,@p1='2010-02-15 01:24:00' 

(Ceci est le SQL réelle prise de SQL Profiler sur SQL Server 2008.)

Le plan de requête généré quand je lance cette SQL de Query Analyser est parfait. Il utilise un index contenant VisitedStore, Bot, SessionDate. La requête retourne instantanément.

Toutefois, lorsque j'exécute ceci à partir de C# (avec LINQ), un plan de requête différent est utilisé qui est si inefficace qu'il ne revient même pas en 60 secondes. Ce plan de requête tente d'effectuer une recherche de clé sur la clé primaire en cluster contenant quelques millions de lignes. Il n'a aucune chance de revenir. Ce que je ne peux tout simplement pas comprendre, c'est que le même SQL EXACT est en cours d'exécution - soit à partir de LINQ ou à partir de Query Analyzer mais le plan de requête est différent.

J'ai couru les deux requêtes plusieurs fois et elles fonctionnent maintenant isolément de toutes les autres requêtes. La date est DateTime.Now.AddDays(-7), mais j'ai même codé en dur cette date pour éliminer les problèmes de mise en cache.

Y at-il quelque chose que je peux changer dans LINQ to SQL pour affecter le plan de requête ou essayer de déboguer cela plus loin? Je suis très très confus!

+0

Comment afficher le plan d'exécution dans différents contextes: http://stackoverflow.com/questions/7359702/how-do-i-obtain-a- query-execution-plan –

Répondre

6

Ceci est un problème relativement courant qui m'a surpris aussi quand je l'ai vu pour la première fois. La première chose à faire est de vous assurer que vos statistiques sont à jour. Vous pouvez vérifier l'âge des statistiques avec:

SELECT 
    object_name = Object_Name(ind.object_id), 
    IndexName = ind.name, 
    StatisticsDate = STATS_DATE(ind.object_id, ind.index_id) 
FROM SYS.INDEXES ind 
order by STATS_DATE(ind.object_id, ind.index_id) desc 

Les statistiques doivent être mises à jour dans un plan de maintenance hebdomadaire. Pour une solution rapide, exécutez la commande suivante pour mettre à jour toutes les statistiques dans votre base de données:

exec sp_updatestats 

Outre les statistiques, une autre chose que vous pouvez vérifier est le SET options. Ils peuvent être différents entre Query Analyzer et votre application Linq2Sql.

Une autre possibilité est que SQL Server utilise un ancien plan mis en cache pour votre requête Linq2Sql. Les plans peuvent être mis en cache pour chaque utilisateur, donc si vous exécutez Query Analyzer en tant qu'utilisateur différent, cela peut expliquer différents plans. Normalement, vous pouvez ajouter Option (RECOMPILE) à la requête de l'application, mais je suppose que c'est dur avec Linq2Sql. Vous pouvez effacer tout le cache avec DBCC FREEPROCCACHE et voir si cela accélère la requête Linq2Sql.

+0

J'ai exécuté sp_updatestats qui a pris environ 7 minutes. alors j'ai couru DBCC FREEPROCCACHE qui est retourné instantanément sans erreurs. toujours le même comportement cependant. Le SELECT que vous avez fourni montre maintenant la date d'aujourd'hui pour toutes les statistiques (dont certaines avaient 2 ans auparavant!). Je peux avoir à essayer avec un proc stocké. essayez de comparer les options SET demain. Merci! –

+0

btw.Même dans LINQ, il semble correct si la date est dans les dernières 48 heures (pas sûr quel plan de requête c'est, mais peut-être qu'il y a assez peu de lignes pour qu'une analyse soit correcte). Une fois que je passe au-dessus de 60 heures, il passe à l'autre plan de requête et ne revient jamais. mais à partir de Query Analyzer je peux faire un mois, année, 2 ans et il revient instantanément (c'est un compte de 233000 lignes)! encore le même SQL exact pris du profileur. wierd ... –

+0

Si votre première requête LINQ est dans les 48 heures, peut-être que SQL Server générera un plan qui optimise pour ce cas. Que se passe-t-il si vous dbcc freeproccache' et que la première requête dure plus de 60 heures? Pensez également à réécrire le Linq2Sql en utilisant ExecuteQuery (http://msdn.microsoft.com/en-us/library/bb399403.aspx), qui vous permet de spécifier 'option (recompiler)' – Andomar

0

est passé à une procédure stockée et le même SQL fonctionne correctement. aimerais vraiment savoir ce qui se passe mais ne peut pas passer plus de temps à ce sujet maintenant. heureusement, dans ce cas, la requête n'était pas trop dynamique.

nous espérons que cela aide au moins tout le monde dans le même bateau que moi

Questions connexes