Pourquoi certaines requêtes SQL sont-elles beaucoup plus lentes lorsqu'elles sont utilisées avec SqlCommand?

StackOverflow https://stackoverflow.com/questions/801909

  •  03-07-2019
  •  | 
  •  

Question

J'ai une procédure stockée qui s'exécute beaucoup plus rapidement à partir de Sql Server Management Studio (2 secondes) que lorsqu'elle est exécutée avec System.Data.SqlClient.SqlCommand (délai d'expiration après 2 minutes).

Quelle pourrait en être la raison?

Détails: Sql Server Management Studio s'exécute en 2 secondes (sur la base de production):

EXEC sp_Stat
    @DepartmentID = NULL

Dans .NET / C #, le délai suivant expire après 2 minutes (sur la base de données de production):

string selectCommand = @"
EXEC sp_Stat
    @DepartmentID = NULL";
string connectionString = "server=***;database=***;user id=***;pwd=***";
using (SqlConnection connection = new SqlConnection(connectionString))
{
    using (SqlCommand command = new SqlCommand(selectCommand, connection))
    {
        connection.Open();
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
            }
        }
    }
}

J'ai également essayé avec selectCommand = "sp_Stat", , CommandType = StoredProcedure et un SqlParameter , mais le résultat est identique. / p>

Et sans EXEC , le résultat est identique.

Dans une base de données de développement presque vide, les deux cas se terminent en moins d'une seconde. C'est donc lié au fait qu'il y a beaucoup de données dans la base de données, mais cela ne semble provenir que de .NET ...

Ce que Marc Gravell a écrit sur différentes valeurs SET fait la différence dans le cas présenté.

SQL Server Profiler a montré que SQL Server Management Studio exécute les SET suivants, contrairement au fournisseur de données client .NET Sql:


SET ROWCOUNT 0 
SET TEXTSIZE 2147483647 
SET NOCOUNT OFF 
SET CONCAT_NULL_YIELDS_NULL ON 
SET ARITHABORT ON 
SET LOCK_TIMEOUT -1 
SET QUERY_GOVERNOR_COST_LIMIT 0 
SET DEADLOCK_PRIORITY NORMAL 
SET TRANSACTION ISOLATION LEVEL READ COMMITTED 
SET ANSI_NULLS ON 
SET ANSI_NULL_DFLT_ON ON 
SET ANSI_PADDING ON 
SET ANSI_WARNINGS ON 
SET CURSOR_CLOSE_ON_COMMIT OFF 
SET IMPLICIT_TRANSACTIONS OFF 
SET QUOTED_IDENTIFIER ON
SET NOEXEC, PARSEONLY, FMTONLY OFF

Lorsque j'ai inclus ces éléments, la même requête a pris le même temps dans SSMS et .NET. Et le SET responsable est ...

SET ARITHABORT ON

Qu'est-ce que j'ai appris? Peut-être utiliser un profileur au lieu de deviner ...

(Au début, la solution semblait être liée à la détection de paramètres. Mais j'avais mélangé certaines choses ...)

Était-ce utile?

La solution

Un autre élément important peut être le le SET . options qui sont activées. Certaines de ces options modifient suffisamment le plan de requête pour modifier le profil. Certains peuvent avoir un impact énorme si vous regardez (par exemple) une colonne calculée + persistée (et éventuellement indexée): si les options SET ne sont pas compatibles, il peut être obligé de recalculer les valeurs, plutôt que d'utiliser la valeur indexée - qui peut changer une recherche d'index en une analyse de table + calcul.

Essayez d’utiliser le profileur pour voir quelles options SET sont "en cours de lecture", et voyez si l’utilisation de ces options change les choses.

La chaîne de connexion est un autre impact. par exemple, si vous activez MARS qui peut modifier le comportement de manière subtile.

Enfin, les transactions (implicites ( TransactionScope ) ou explicites) peuvent avoir un impact énorme , en fonction du niveau d'isolement.

Autres conseils

Cela est presque certainement dû à un plan de requête mis en cache «incorrect». C’est ce qui a été dit à quelques reprises sur SO.

Avez-vous des statistiques à jour? Un plan de maintenance d'index régulier?

Vous pouvez vérifier si cela est définitivement dû au plan de requête mis en cache en l'ajoutant à la définition de votre procédure stockée:

CREATE PROCEDURE usp_MyProcedure WITH RECOMPILE...

Ceci réindexera une base de données entière (attention si la base de données est très volumineuse!):

exec sp_msforeachtable "dbcc dbreindex('?')"

Messages SO:

Grande différence entre heure d'exécution de la procédure stockée entre Managment Studio et TableAdapter.

Détection de paramètre (ou usurpation) dans SQL Server

optimiser pour inconnu pour SQL Server 2005?

plan d'exécution différent pour la même procédure stockée

Avait un problème similaire et il s'est avéré que MultipleActiveResultSets = true dans la chaîne de connexion (censée avoir un impact minimal) rendait l'extraction d'enregistrements de 1,5 million via une connexion distante prenant 25 minutes au lieu d'environ 2 minutes.

Nous avions un problème similaire: une requête se terminait en 2 secondes dans SSMS et prenait plus de 90 secondes lorsqu'elle était appelée depuis un client .NET (nous avons écrit plusieurs applications / sites VB / C # pour le tester.)

Nous avons suspecté que le plan de requête serait différent et nous l'avons réécrit avec des indications de boucle explicites ("jointure de boucle interne" et "avec index"). Cela a résolu le problème.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top