Comment puis-je résoudre un problème de piscine de connexion entre ASP.NET et SQL Server?
ces derniers jours, nous avons vu ce message d'erreur sur notre site Web trop:
"Délai d'attente expiré. La période de temps mort s'est écoulé avant l'obtention d'un connexion depuis la piscine. Cela peut ont eu lieu parce que tous les les connexions étaient en usage et Max pool la taille a été atteint."
nous n'avons rien changé dans notre code depuis un moment. J'ai révisé le code pour vérifier les connexions ouvertes qui n'ont pas fermé, mais j'ai trouvé tout pour être bien.
-
comment résoudre ce problème?
-
Dois-je modifier cette piscine?
-
Comment puis-je modifier le nombre maximum de connexions de cette piscine?
-
Quelle est la valeur recommandée pour un site web très fréquenté?
mise à jour:
est-ce que je dois éditer quelque chose dans IIS?
mise à jour:
j'ai trouvé que le nombre de connexions actives sont n'importe où de 15 à 31, et j'ai trouvé que le nombre maximum autorisé de connexions configurées dans le serveur SQL est plus de 3200 connexions, est 31 de trop ou devrais-je éditer quelque chose dans le ASP.NET le config nement?
17 réponses
dans la plupart des cas, les problèmes de mise en commun des connexions sont liés à des fuites de connexion."Votre application ne ferme probablement pas ses connexions de base de données correctement et systématiquement. Lorsque vous laissez les connexions ouvertes, elles restent bloquées jusqu'à ce que le ramasseur D'ordures .NET les ferme pour vous en appelant leur méthode Finalize()
.
vous voulez Vous assurer que vous êtes vraiment la fermeture de la connexion . Par exemple, le code suivant provoque une fuite de connexion, si le code entre .Open
et Close
jette une exception:
var connection = new SqlConnection(connectionString);
connection.Open();
// some code
connection.Close();
la bonne façon serait celle-ci:
var connection = new SqlConnection(ConnectionString);
try
{
connection.Open();
someCall (connection);
}
finally
{
connection.Close();
}
ou
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
someCall(connection);
}
lorsque votre fonction renvoie une connexion à partir d'une méthode de classe assurez-vous de la mettre en cache localement et d'appeler sa méthode Close
. Vous perdrez une connexion en utilisant ce code par exemple:
var command = new OleDbCommand(someUpdateQuery, getConnection());
result = command.ExecuteNonQuery();
connection().Close();
la connexion revenue du premier appel à getConnection()
n'est pas fermée. Au lieu de fermer votre connexion, cette ligne crée une nouvelle et essaie de la fermer.
si vous utilisez SqlDataReader
ou un OleDbDataReader
, fermez-les. Même si fermer la connexion elle-même semble faire l'affaire, mettez l'effort supplémentaire de fermer vos objets de lecteur de données explicitement lorsque vous les utilisez.
cet article " pourquoi une piscine de connexion déborde-t-elle? " à partir de MSDN/SQL Magazine explique beaucoup de détails, et suggère des stratégies de débogage:
- Exécuter
sp_who
ousp_who2
. Ces procédures stockées dans le système renvoient des informations de la table systèmesysprocesses
qui montre l'état et les informations de tous les processus de travail. Généralement, vous verrez un identifiant de processus de serveur (SPID) par connexion. Si vous avez nommé votre connexion en utilisant l'argument nom D'Application dans la chaîne de connexion, vos connexions de travail seront faciles à trouver. - utilisez SQL Server Profiler avec le modèle
TSQL_Replay
pour tracer les connexions ouvertes. Si vous êtes familier avec Profiler, cette méthode est plus facile que polling en utilisant sp_who. - utilisez le moniteur de Performance pour surveiller les piscines et les connexions. Je discuter de cette méthode dans un instant.
- compteurs de performances des moniteurs dans le code. Vous pouvez surveiller la santé de votre pool de connexions et le nombre de connexions établies en utilisant des routines pour extraire les compteurs ou en utilisant les nouveaux contrôles.net PerformanceCounter.
lors de l'installation de .net Framework v4.6.1 Nos connexions à une base de données distante ont immédiatement commencé à chronométrer en raison de ce changement .
pour fixer il suffit d'ajouter le paramètre TransparentNetworkIPResolution
dans la chaîne de connexion et de le définir à false :
Server=myServerName; Database=myDataBase;Trusted_Connection = True; TransparentNetworkIPResolution=False
à moins que votre utilisation a augmenté beaucoup, il semble peu probable qu'il ya juste un arriéré de travail. IMO, l'option la plus probable est que quelque chose utilise des connexions et ne les libère pas rapidement. Êtes-vous sûr vous utilisez using
dans tous les cas? Ou (par quelque mécanisme que ce soit) en libérant les connexions?
avez-vous vérifié les lecteurs de données qui ne sont pas fermés et la réponse.redirige avant de fermer la connexion ou un lecteur de données. Les connexions restent ouvertes lorsque vous ne les fermez pas avant une redirection.
nous rencontrons ce problème de temps en temps sur notre site web aussi bien. Le coupable dans notre cas, c'est nos statistiques/index qui deviennent périmés. Cela provoque une requête précédemment en cours d'exécution rapide à (éventuellement) devenir lent et time out.
essayez de mettre à jour les statistiques et/ou de reconstruire les index sur les tables affectées par la requête et voir si cela aide.
vous pouvez spécifier la taille minimale et maximale du pool en spécifiant MinPoolSize=xyz
et/ou MaxPoolSize=xyz
dans la chaîne de connexion. Cette cause du problème pourrait être une autre chose, cependant.
j'ai moi aussi rencontré ce problème lors de l'utilisation d'une couche de données de tiers dans une de mes applications .NET. Le problème était que la couche ne fermait pas les connexions correctement.
nous avons jeté la couche et nous en avons créé une nous-mêmes, qui se ferme toujours et dispose des connexions. Depuis lors, nous n'avons pas l'erreur de plus.
si vous travaillez sur un code d'héritage complexe où une simple utilisation (..) {..} n'est pas possible - comme je l'ai été - vous pouvez consulter l'extrait de code que j'ai posté dans cette DONC, la question un moyen pour déterminer la pile des appels de la création de la connexion lorsqu'une connexion est potentiellement fuite (pas fermé après un délai d'attente). Cela rend assez facile de repérer la cause des fuites.
ceci est principalement dû au fait que la connexion n'a pas été fermée dans l'application. Utilisez "MinPoolSize" et" MaxPoolSize " dans la chaîne de connexion.
dans mon cas, je ne fermais pas L'objet DataReader.
using (SqlCommand dbCmd = new SqlCommand("*StoredProcedureName*"))
using (dbCmd.Connection = new SqlConnection(WebConfigurationAccess.ConnectionString))
{
dbCmd.CommandType = CommandType.StoredProcedure;
//Add parametres
dbCmd.Parameters.Add(new SqlParameter("@ID", SqlDbType.Int)).Value = ID;
.....
.....
dbCmd.Connection.Open();
var dr = dbCmd.ExecuteReader(); //created a Data reader here
dr.Close(); //gotta close the data reader
//dbCmd.Connection.Close(); //don't need this as 'using' statement should take care of this in its implicit dispose method.
}
utilisez ceci:
finally
{
connection.Close();
connection.Dispose();
SqlConnection.ClearPool();
}
Vous pouvez essayer aussi, pour résoudre les problème de délai d'attente:
si vous n'avez pas ajouté httpRuntime à votre webconfig, ajoutez cela dans <system.web>
tag
<sytem.web>
<httpRuntime maxRequestLength="20000" executionTimeout="999999"/>
</system.web>
et
modifiez votre chaîne de connexion comme ceci;
<add name="connstring" connectionString="Data Source=DSourceName;Initial Catalog=DBName;Integrated Security=True;Max Pool Size=50000;Pooling=True;" providerName="System.Data.SqlClient" />
à la dernière utilisation
try
{...}
catch
{...}
finaly
{
connection.close();
}
ce problème que j'avais dans mon code. Je vais coller un exemple de code que j'ai survolé est venu en dessous de l'erreur. Le délai écoulé avant l'obtention d'une connexion à partir de la piscine. Cela peut s'être produit parce que toutes les connexions groupées étaient utilisées et que la taille maximale de la piscine était atteinte.
String query = "insert into STATION2(ID,CITY,STATE,LAT_N,LONG_W) values('" + a1 + "','" + b1 + "','" + c1 + "','" + d1 + "','" + f1 + "')";
//,'" + d1 + "','" + f1 + "','" + g1 + "'
SqlConnection con = new SqlConnection(mycon);
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = query;
cmd.Connection = con;
cmd.ExecuteNonQuery();
**con.Close();**
Vous voulez fermer la connexion à chaque fois. Avant cela, je ne nous ai pas fait la connexion étroite en raison de cela, j'ai eu une erreur. Après l'ajout de l'instruction de fermeture i ont dépassé cette erreur
en plus des solutions publiées....
en traitant avec 1000 pages de code d'héritage, chacun appelant un Gers commun plusieurs fois, voici une autre façon de résoudre le problème:
dans une DLL commune existante, nous avons ajouté le CommandBehavior.CloseConnection option:
static public IDataReader GetRS(String Sql)
{
SqlConnection dbconn = new SqlConnection(DB.GetDBConn());
dbconn.Open();
SqlCommand cmd = new SqlCommand(Sql, dbconn);
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
ensuite dans chaque page, aussi longtemps que vous fermez le lecteur de données, la connexion est également automatiquement fermé afin de connexion les fuites sont empêchés.
IDataReader rs = CommonDLL.GetRS("select * from table");
while (rs.Read())
{
// do something
}
rs.Close(); // this also closes the connection
vous avez divulgué des connexions sur votre code. Vous pouvez essayer d'utiliser l'utilisation pour certifier que vous les fermez.
Using (SqlConnection sqlconnection1 = new SqlConnection(“Server=.\SQLEXPRESS ;Integrated security=sspi;connection timeout=5”)) {
sqlconnection1.Open();
SqlCommand sqlcommand1 = sqlconnection1.CreateCommand();
sqlcommand1.CommandText = “raiserror (‘This is a fake exception’, 17,1)”;
sqlcommand1.ExecuteNonQuery(); //this throws a SqlException every time it is called.
sqlconnection1.Close(); //Still never gets called.
} // Here sqlconnection1.Dispose is _guaranteed_
ce problème que j'ai rencontré auparavant. Il a fini par être un problème avec le pare-feu. J'ai juste ajouté une règle au pare-feu. J'ai dû ouvrir le port 1433
pour que le serveur SQL puisse se connecter au serveur.