2010-12-09 4 views
4

J'ai une requête LINQ qui récupère les lignes d'une vue basée sur une colonne id (où id = id @)LINQ vs (app ou .NET vs studio de gestion SQL Server) SQL

Cette requête prend 4 secondes pour courir. J'ai utilisé SQL Server Profiler pour inspecter la requête qui est exécutée par linq, et si je copie cette requête directement au studio de gestion et à l'exécution, la requête ne prend que 56ms.

Cette augmentation de temps exponentielle est cohérente dans toutes les requêtes linq aux vues de mon application. Quelle pourrait être la cause de cette durée d'exécution étendue dans mon application (WPF) lorsque les mêmes requêtes exécutent < 100ms?

== == EDIT

J'ai réussi à isoler davantage, les commentaires montrent la durée de profileur;

/* 3953ms, 111487 reads */ 
context.SkuView.Where(p => p.TermId == 35 && !p.IsDeleted).ToList(); 

/* 90ms, 173 reads */ 
context.SkuView.Where(p => p.TermId == 35).ToList(); 

Si je colle les requêtes linq (sql rendues) directement dans ssms je reçois;

/* 250ms, 173 reads */ 
SELECT * FROM SkuView WHERE TermId == 35 AND IsDeleted = 0 

/* 250ms, 173 reads */ 
SELECT * FROM SkuView WHERE TermId == 35 

Le problème a quelque chose à voir avec le lecture compte par LINQ lors de l'utilisation p.IsDeleted ...

+0

Wow, c'est une différence de temps énorme. Pour être clair, les 4 secondes à courir est le temps qu'il faut à la requête pour exécuter selon SQL Profiler? – Pandincus

+0

correct. linq exécute la requête à l'aide de exec sp_executesql et le profileur affiche un temps d'exécution de 4 secondes. Si je copie exactement exec _sp_executesql qui vient de s'exécuter, et l'exécuter dans SSMS, profileur montre 58ms –

+0

L2S n'est pas le moyen le plus efficace d'interroger une base de données, mais c'est une différence assez massive. – Phill

Répondre

7

coupables possibles sont:

  • affirmation. Lorsqu'elles sont exécutées à partir de Linq, les autres activités d'application bloquent les lignes et provoquent l'arrêt de la requête en attente de verrous. Lorsqu'il est exécuté à partir de SSMS, il n'y a pas d'autre activité et la requête se termine donc rapidement.
  • différence dans les types de paramètres. Le passage d'un paramètre NVARCHAR à une comparaison avec une colonne VARCHAR entraîne une analyse complète (l'index ne peut pas être utilisé en raison des règles Data Type Precedence). Cela est dû à un mauvais LINQ ColumnAttribute. Lorsqu'il est exécuté à partir de SSMS, la requête est généralement copiée de manière incorrecte et le type de paramètre est modifié en VARCHAR.
  • fonctionnement à froid par rapport à l'essai à chaud. La requête est exécutée par LINq en premier, ce qui réchauffe le cache (récupère les données du disque dans la mémoire). Lors d'une nouvelle exécution à partir de SSMS, il n'y a pas d'attente pour les E/S.

Dans tous les cas, les outils à étudier sont à votre disposition.

  • comparer le nombre de lectures des deux requêtes (RPC:Complete, TSQL:BatchComplete événements Profiler)
  • compare les propositions. Utilisez l'événement Showplan XML.
  • regarder ce qui est la requête Linq faire: sys.dm_exec_requests wait_type, wait_time et colonnes wait_resource
  • comparer les requêtes statistiques pour les deux cas: sys.dm_exec_query_stats. les choses à rechercher sont de grandes différences entre les deux cas dans logical_reads et physical_reads, indiquant des plans très différents (scan vs. seek), ou des différences sauvages dans elapsed_time mais worker_time similaire (indiquant un blocage, des verrous probables).
+0

Remus merci. Selon l'édition ci-dessus, les lectures sont énormes sur la requête affectée. essayer de tirer xml showplan sur profiler atm. En supposant que le plan d'exécution est différent, des pointeurs sur la façon de résoudre ce problème? –

+0

essayez d'afficher le plan. Plan original XML, pas le rendu graphique. Voir http://msdn.microsoft.com/en-us/library/ms179321.aspx –

+0

les plans d'exécution sont radicalement différents; longue requête; http://pastebin.com/kqTMKCdz requête courte; http://pastebin.com/f7difnj6 –

0

Cette requête prend 4 secondes pour courir ... si je copie cette requête directement au studio de gestion et exécution, la requête ne prend 56 ms.

Il n'y a pas de différence magique entre votre application et le studio de gestion. Les deux programmes créent une connexion à la base de données et émettent des commandes de texte sql (une fois dans le serveur de base de données: un plan de requête est généré, les E/S et le CPU sont dépensés et les résultats sont renvoyés). Puisque la seule différence ici est "app faisant une connexion", vous devriez inspecter les connexions. Commencez avec les chaînes de connexion ...

En supposant qu'il n'y a pas de problème dans la chaîne de connexion, passez à SET settings. En particulier, SET ANSI_NULLS doit être activé, car il peut interférer avec les colonnes calculées et les vues avec des index clusterisés.

2

La mise à jour des statistiques sur la base de données a résolu ce problème.

exec sp_updatestats 

Merci beaucoup à Remus pour l'apprentissage;)

+0

ceci est seulement un correctif temporaire. ajouter/modifier des données entraînera lentement la dégradation des plans d'exécution. –

0

ARITHABORT est activée par défaut dans SSMS et désactivé par défaut pour une connexion SqlClient.

Ce résoudre un problème similaire pour moi:

new SqlCommand("SET ARITHABORT ON", connection).ExecuteNonQuery();