2011-10-03 3 views
17

J'ai une requête assez simple que je continue à obtenir des délais (il faut plus de trois minutes pour terminer, je l'ai arrêté tôt pour que je puisse poster cette question) sur lorsqu'il s'exécute dans le code Cependant, lorsque j'exécute la même requête à partir du même ordinateur dans Sql Server Management Studio, la requête ne prend que 2532 ms la première requête lorsque les données ne sont pas mises en cache sur le serveur et 524 ms pour les requêtes répétées.Requête extrêmement lente dans le code mais rapide dans SSMS

Voici mon C# Code

using (var conn = new SqlConnection("Data Source=backend.example.com;Connect Timeout=5;Initial Catalog=Logs;Persist Security Info=True;User ID=backendAPI;Password=Redacted")) 
       using (var ada = new SqlDataAdapter(String.Format(@" 
SELECT [PK_JOB],[CLIENT_ID],[STATUS],[LOG_NAME],dt 
FROM [ES_HISTORY] 
inner join [es_history_dt] on [PK_JOB] = [es_historyid] 
Where client_id = @clientID and dt > @dt and (job_type > 4 {0}) {1} 
Order by dt desc" 
    , where.ToString(), (cbShowOnlyFailed.Checked ? "and Status = 1" : "")), conn)) 
{ 
    ada.SelectCommand.Parameters.AddWithValue("@clientID", ClientID); 
    ada.SelectCommand.Parameters.AddWithValue("@dt", dtpFilter.Value); 
    //ada.SelectCommand.CommandTimeout = 60; 
    conn.Open(); 
    Logs.Clear(); 
    ada.Fill(Logs); //Time out exception for 30 sec limit. 
} 

voici mon code que je courais dans SSMS, je tire à droite de ada.SelectCommand.CommandText

declare @clientID varchar(200) 
set @clientID = '138' 
declare @dt datetime 
set @dt = '9/19/2011 12:00:00 AM' 

SELECT [PK_JOB],[CLIENT_ID],[STATUS],[LOG_NAME],dt 
FROM [ES_HISTORY] 
inner join [es_history_dt] on [PK_JOB] = [es_historyid] 
Where client_id = @clientID and dt > @dt and (job_type > 4 or job_type = 0 or job_type = 1 or job_type = 4) 
Order by dt desc 

Quelle est l'origine de l'inconsistance majeure pour la différence de temps?


Pour garder la section des commentaires propre, je vais répondre à quelques questions ici.

Le même ordinateur et la même connexion sont utilisés à la fois pour l'application et pour les ssms.

Seulement 15 lignes sont retournées dans mon exemple de requête. Cependant, es_history contient 11351699 rows et es_history_dt contient 8588493 rows. Les deux tables sont bien indexées et le plan d'exécution dans SSMS indique qu'elles utilisent des recherches d'index pour les recherches, ce qui en fait des recherches rapides. Le programme se comporte comme s'il n'utilisait pas les index pour la version C# de la requête.

+0

Avez-vous utilisé le même utilisateur dans SSMS que dans le code? – bzlm

+1

Combien de lignes sont renvoyées par cette requête? –

+0

@hugh s'il vous plaît voir ma mise à jour .. –

Répondre

31

Votre code dans SSMS n'est pas le même que celui que vous avez exécuté dans votre application. Cette ligne dans votre application ajoute un paramètre nvarchar:

ada.SelectCommand.Parameters.AddWithValue("@clientID", ClientID); 

alors que dans le script SSMS vous déclarer comme VARCHAR:

declare @clientID varchar(200) 

En raison des règles de Data Type Precedence l'expression Where client_id = @clientID dans votre requête n'est pas SARG -able où @clientID est de type NVARCHAR (je fais un acte de foi et suppose que la colonne client_id est de type VARCHAR). L'application force ainsi un balayage de table où la requête SSMS peut faire une recherche rapide de clé. Ceci est un problème bien connu et compris avec l'utilisation de Parameters.AddWithValue et a été discuté dans de nombreux articles avant, par exemple. voir How Data Access Code Affects Database Performance. Une fois que le problème est compris, les solutions sont très simples:

Le sapin Cette solution est supérieure parce qu'elle résout le problème de pollution de la cache en plus du problème de capacité SARG.

Je recommande aussi de lire Slow in the Application, Fast in SSMS? Understanding Performance Mysteries

+0

En fait j'ai utilisé varchar parce que l'interface pour la fonction passé l'ID du client sous la forme d'une chaîne. J'ai vérifié le schéma et Client_ID est en fait un int. Le changer dans mon code pour convertir la chaîne passée en int avant l'exécution de la requête a résolu le problème. Je vous remercie! –

+0

Merci aussi pour le dernier lien, c'est très utile. –

0

Exécutez le profileur sur votre C# connexion - il peut y avoir d'autres activités à faire que vous n'êtes pas au courant.

0

Capturez le plan d'exécution à partir des deux SSMS lorsque vous exécutez manuellement votre requête, puis à partir de Profiler lorsque vous exécutez votre application. Compare et nuance.

0

Exécutez DBCC FREEPROCCACHE, comme suggéré here, juste pour vous assurer que le problème n'est pas dû à un plan d'exécution de requête obsolète.

Questions connexes