2011-08-15 88 views
2

我需要将包含特定命名表的服务器的附加数据库列表填充到两个下拉框中。我目前的方法是这样的。获取包含表的数据库列表的有效方法

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()); 

这可以工作,但是在具有205个附加数据库的服务器上运行需要44.6秒。

任何人都可以给我任何关于如何加快此操作的建议吗?我愿意使用SMO等其他技术,进行更多的客户端处理,或者将其作为服务器上某种形式的复杂查询运行。只要我根据两个表名得到两个列表,它就能满足我的需求。


下面是更新后的版本,使我的运行时间降到了第二位,这要归功于总的建议。

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(); 
      }); 
    } 

} 
+0

你有什么可以分析,看看时间正在接受?我的猜测主要是打开你可能无法避免的连接。 – pstanton

+0

@pstanton我只打开两个连接并重新使用它们,如果表存在,则花费在查询上的时间。 –

回答

4

我会在一个单独的线程中运行每个线程,然后在继续之前加入它们。当然,您需要使用线程安全结构来执行此操作,但这样可以让您同时发送所有请求,因此您不必等待每个请求都转到下一个请求。

如果你有200个数据库,你可能想要为每个线程使用一个线程池而不是一个线程,但是200线程不是那么多......实验和配置文件,但这是我的一般方法采取。

+0

也会确保在它们之间共享它们之间的连接 –

+0

将该查询放在'Parallel.ForEach'中会使我的运行时间缩短到0.8秒。 –

+0

非常好。我不是一个C#人,所以我不能给你具体的东西。很高兴通用的解决方案可以应用您对图书馆的了解,以获得成功! .8比44好多了! :-D – corsiKa

相关问题