2008-11-20 20 views
0

我想要做的是在許多Oracle數據庫(至少一打)上運行相同的SQL選擇,並在GridView中顯示輸出。在ASP.NET中查詢許多數據庫的好方法

我把一些有用的東西一起砍了,但不幸的是它很慢。我認爲這個事實加劇了這樣一個事實,即至少有一個數據庫總是無法訪問,或者處於錯誤狀態。

除了緩慢,我不禁認爲這不是最好的方式,也不是'.NET'。

我以前寫過類似於PHP的簡單循環,它依次連接到每個數據庫,運行sql並編寫另一個<tr>,並且對於給定的查詢它的工作速度至少快兩倍。但我並不滿意,我想提高我的知識!

我學習C#和ASP.NET所以請原諒可怕的代碼:)

public void BindData(string mySQL) 
    { 
     OracleConnection myConnection; 
     OracleDataAdapter TempDataAdapter; 
     DataSet MainDataSet = new DataSet(); 
     DataTable MainDataTable = new DataTable(); 
     DataSet TempDataSet; 
     DataTable TempDataTable; 
     string connectionString = ""; 
     Label1.Visible = false; 
     Label1.Text = ""; 

     foreach (ListItem li in CheckBoxList1.Items) 
     { 
      if (li.Selected) 
      { 
       connectionString = "Data Source=" + li.Text + ""; 
       connectionString += ";Persist Security Info=True;User ID=user;Password=pass;Unicode=True"; 
       myConnection = new OracleConnection(connectionString); 
       try 
       { 
        TempDataAdapter = new OracleDataAdapter(mySQL, myConnection); 
        TempDataSet = new DataSet(); 
        TempDataTable = new DataTable(); 
        TempDataAdapter.Fill(TempDataSet); 
        TempDataTable = TempDataSet.Tables[0].Copy(); 
        /* If the main dataset is empty, create a table by cloning from temp dataset, otherwise 
        copy all rows to existing table.*/ 
        if (MainDataSet.Tables.Count == 0) 
        { 
         MainDataSet.Tables.Add(TempDataTable); 
         MainDataTable = MainDataSet.Tables[0]; 
        } 
        else 
        { 
         foreach (DataRow dr in TempDataTable.Rows) 
         { 
          MainDataTable.ImportRow(dr); 
         } 
        } 
       } 
       catch (OracleException e) 
       { 
        Label1.Visible = true; 
        Label1.Text = Label1.Text + e.Message + " on " + li.Text + "<br>"; 

       } 
       finally 
       { 
        if (myConnection != null) 
        { 
         myConnection.Close(); 
         myConnection = null; 
        } 
        TempDataSet = null; 
        TempDataAdapter = null; 
        TempDataTable = null; 

       } 
      } 
     } 
     GridView1.DataSourceID = String.Empty; 
     if (MainDataSet.Tables.Count != 0) 
     { 
     GridView1.DataSource = MainDataSet; 
      if (GridView1.DataSource != null) 
      { 
       GridView1.DataBind(); 
      } 
     } 
    } 
    protected void Button1_Click(object sender, EventArgs e) 
    { 
     BindData(TextBox1.Text); 
    } 

謝謝!

更新:SQL代碼各不相同,對於測試,我使用了非常簡單的查詢,如select sysdate from dualselect name from v$database。在最終的使用中,它會複雜得多,我的想法是,我應該可以運行任何東西,因此可以運行幾乎所有的東西,因此更新:從ASP.NET代碼連接到許多數據庫而不是在一個或所有dbs上存儲過程,或複製到一個db,是雙重的。首先,有問題的dbs經常更新幾個類似生產環境的副本(通常是爲每個客戶端開發,測試和支持),因此對於實際的dbs所做的任何事情都必須定期更新或重新定義,因爲它們無論如何都會被重新加載。其次,我不知道什麼樣的查詢可以運行,這個表單可以讓我輸入例如select count (name) from dbusers而不必先考慮將dbusers表複製到主數據庫。

回答

3

如果DataTable對象上運行DataAdapter.Fill方法方法表會用查詢結果更新。因此,不是創建新的DataTable和DataSet對象,而是手動複製DataRows,您可以將行添加到同一個表中。

嘗試是這樣的(在未經測試的C#代碼):

public void BindData(string mySQL) 
{ 
    OracleConnection myConnection; 
    // Empty connection string for now 
    OracleDataAdapter MainDataAdapter = new OracleDataAdapter(mySQL, ""); 
    DataTable MainDataTable = new DataTable(); 
    string connectionString = ""; 
    Label1.Visible = false; 
    Label1.Text = ""; 

    foreach (ListItem li in CheckBoxList1.Items) 
    { 
    if (li.Selected) 
    { 
     connectionString = "Data Source=" + li.Text + ""; 
     connectionString += ";Persist Security Info=True;User ID=user;Password=pass;Unicode=True"; 
     MainDataAdapter.SelectCommand.Connection.ConnectionString = connectionString 
     try 
     { 
     MainDataAdapter.Fill(MainDataTable); 
     } 
     catch (OracleException e) 
     { 
     Label1.Visible = true; 
     Label1.Text = Label1.Text + e.Message + " on " + li.Text + "<br>"; 
     } 
    } 
    } 
    GridView1.DataSourceID = String.Empty; 
    GridView1.DataSource = MainDataTable; 
    GridView1.DataBind(); 
} 

我做了如下修改:

  • 創建一個數據適配器,並使用你的MySQL查詢
  • 賦予它一個SELECT命令
  • 給連接一個空的連接字符串
  • 創建一個數據表對象並刪除數據集(如果您的查詢返回多個數據集,您只需要它們行)
  • 改變了你循環只設置SelectCommand的連接字符串(您可能必須把這個變成帶更換新的SelectCommand)
  • 刪除了的Connection.close()調用。 DataAdapter自動執行此操作。

而那就是它。如果您的數據庫處於脫機狀態,您仍然會遇到速度減慢,但至少代碼更簡單快捷,因爲您不必複製表格之間的所有行。

還有一件事。您可以在連接字符串中設置連接的超時時間。嘗試降低這一個。

+0

非常晚的更新...你的代碼實際上幾乎是完美的! 如果更改: MainDataAdapter.SelectCommand.ConnectionString = connectionString to: MainDataAdapter.SelectCommand.Connection.ConnectionString = connectionString; 它很好地工作 – 2009-01-15 11:51:19

2

可能是很多因素導致它很慢。運行緩慢的sql語句是什麼?

如果有人讀,這是使用SQL Server,斯科特·米切爾剛剛寫了一篇很好的文章,以幫助在SQL Server中解決這個問題:Running the Same Query Against Multiple Databases

+0

SQL代碼各不相同,用於測試我已經使用了非常簡單的查詢,例如從dual選擇sysdate或從v $數據庫中選擇名稱。 – 2008-11-21 10:18:25

+0

感謝文章鏈接,這非常有趣,Oracle的原則貫穿始終。 – 2008-11-21 10:20:20

+0

(我的意思是你可以編寫自己的sp_MsForEachDb equivilent for Oracle) – 2008-11-21 10:21:20

0

這聽起來像你可能更有興趣得到這個更通用的問題的答案:如何執行一個長時間運行的任務而不掛用戶界面(ASP或WinForms)?

該問題的答案是使用多個Threads。我會在單獨的線程上執行像這樣的長時間運行的任務,並向用戶顯示當前結果的頁面(自動刷新或使用ajax等)。你甚至可以爲每個可用的處理器創建任務,以充分利用你的機器(使用諸如Parallel Extensions之類的東西);然而這會顯着增加複雜性,並且難以正確地進行。

如果你還沒有在.NET中使用線程的工作有很大的教程可以發現here(由唯一Jon Skeet

1

爲什麼不能在一個Oracle數據庫運行一個存儲過程,並具有存儲過程調用其他數據庫?這是處理鏈接數據庫的正確方法。

1

爲什麼不使用複製來做到這一點...你知道,一箇中央數據庫正在彙集來自其他數據庫的新數據,並對這組數據執行查詢,該數據是從不會將被關閉。