I need to populate two drop-down boxes with a list of attached databases to a server that contain a specifically named table. My current method is this.
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());
This works, however on a server with 205 attached databases it takes 44.6 seconds to run.
Can anyone give me any advice on how to speed this operation up? I am open to using other techniques like SMO, doing more client side processing, or running this as some form of complicated query on the server. As long as I get the two lists based on the two table names it satisfies my needs.
H开发者_Python百科ere is the updated version that brought my run time down to under a second thanks to total's suggestion.
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();
});
}
}
I would run each one in a separate thread and then join them all before you continue. You'll need to use thread safe structures to do this, of course, but this will let you send all your requests at the same time so you don't have to wait for each one to move on to the next one.
You might want to use a threadpool instead of one thread for each one if you have 200 something databases, but then again, 200 threads isn't THAT much... Experiment and profile, but that's the general approach I would take.
精彩评论