J'ai besoin de remplir deux listes déroulantes avec une liste de bases de données attachées à un serveur qui contient une table spécifiquement nommée. Ma méthode actuelle est celle-ci.Méthode efficace pour obtenir une liste de bases de données contenant une table
List<string> dbType1 = new List<string>();
List<string> dbType2 = new List<string>();
using (var conn = new SqlConnection("Data Source=(local);Integrated Security=true"))
using (var cmd = new SqlCommand())
{
conn.Open();
cmd.Connection = conn;
cmd.CommandText = "select name from sys.databases";
using (var innerConn = new SqlConnection("Data Source=(local);Integrated Security=true"))
using (var innerCmd = new SqlCommand())
using (var rdr = cmd.ExecuteReader())
{
innerConn.Open();
innerCmd.Connection = innerConn;
while (rdr.Read())
{
string table = rdr.GetString(0);
innerCmd.CommandText = String.Format("select name from [{0}]..sys.tables where name in 'EF_LAB_FIELDS_DYNA' 'AUTOXPAY_PAYMENTS'", table);
object result = innerCmd.ExecuteScalar();
if(result != null)
{
if ((string)result == "EF_LAB_FIELDS_DYNA")
dbType1.Add(table);
else
dbType2.Add(table);
}
}
}
}
cb.Items.AddRange(dbType1.ToArray());
cb2.Items.AddRange(dbType2.ToArray());
Cela fonctionne, mais sur un serveur avec 205 bases de données attachées, l'exécution prend 44,6 secondes.
Quelqu'un peut-il me donner des conseils sur la façon d'accélérer cette opération? Je suis ouvert à l'utilisation d'autres techniques comme SMO, en faisant plus de traitement côté client, ou en exécutant cela comme une forme de requête compliquée sur le serveur. Tant que j'obtiens les deux listes basées sur les noms des deux tables, cela répond à mes besoins.
Voici la version mise à jour qui a ramené mon temps d'exécution à moins d'une seconde grâce à la suggestion de total.
ConcurrentBag<string> dbType1 = new ConcurrentBag<string>();
ConcurrentBag<string> dbType2 = new ConcurrentBag<string>();
List<string> databases = new List<string>();
using (var conn = new SqlConnection("Data Source=(local);Integrated Security=true"))
using (var cmd = new SqlCommand())
{
conn.Open();
cmd.Connection = conn;
cmd.CommandText = "select name from sys.databases";
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
databases.Add(rdr.GetString(0));
}
Parallel.ForEach(databases,() =>
{
var innerConn = new SqlConnection("Data Source=(local);Integrated Security=true");
var innerCmd = new SqlCommand("", innerConn);
innerConn.Open();
return innerCmd;
},
(database, loopState, localCommand) =>
{
localCommand.CommandText = String.Format("select name from [{0}].sys.tables where name in ('EF_LAB_FIELDS_DYNA', 'AUTOXPAY_PAYMENTS')", database);
object result = localCommand.ExecuteScalar();
if (result != null)
{
if ((string)result == "EF_LAB_FIELDS_DYNA")
dbType1.Add(database);
else
dbType2.Add(database);
}
return localCommand;
},
(localCommand) =>
{
var temp = localCommand.Connection;
localCommand.Dispose();
temp.Dispose();
});
}
}
Avez-vous profilé pour voir où l'heure est prise? ma conjecture ouvre principalement la connexion (s) que vous ne pouvez probablement pas éviter. – pstanton
@pstanton Je n'ouvre que deux connexions et les réutilise, le temps est passé à attendre sur la requête si la table existe. –