0

私がやろうとしているのは、多くの Oracle データベース (少なくとも 12 個) で同じ SQL 選択を実行し、出力を Gridview に表示することです。

機能するものをハックしましたが、残念ながら非常に遅いです。ダースのデータベースのうち少なくとも 1 つが常に到達不能であるか、エラー状態にあるという事実によって悪化していると思います。

遅いだけでなく、それが最善の方法ではなく、「.NET」のようなものでもないと思わずにはいられません。

過去に、各データベースに順番に接続し、SQL を実行して別の を書き込むだけの単純なループを PHP で作成し<tr>たことがあります。これは、特定のクエリに対して少なくとも 2 倍の速さで動作します。でも、それだけでは満足できないので、知識を増やしたいと思います!

私は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 dualorなどの非常に単純なクエリを使用しselect name from v$databaseました。最終的な使用では、はるかに複雑になります。アイデアは、ほとんど何でも実行できるはずです。したがって、BindData(TextBox1.Text)

更新: 1 つまたはすべてのデータベースのストアド プロシージャではなく、ASP.NET コードから多くのデータベースに接続する理由、または 1 つのデータベースに複製する理由は 2 つあります。まず、問題のデータベースは、いくつかの同様の本番環境 (通常は各クライアントの開発、テスト、およびサポート) の頻繁に更新されるレプリカであるため、実際のデータベースに対して行われることはすべて、いずれにせよリロードされるため、定期的に更新またはやり直す必要があります。第二に、実行される可能性のあるクエリの種類が事前にわかりません。このフォームを使用するselect count (name) from dbusersと、最初に dbusers テーブルをマスター データベースに複製することを考える必要なく、12 のデータベースに対して入力するだけで済みます。

4

5 に答える 5

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

次の変更を行いました。

  • 1 つのデータ アダプターを作成し、mySQL クエリを使用して select コマンドを割り当てました
  • 接続に空の接続文字列を指定しました
  • データ テーブル オブジェクトを作成し、データ セットを削除しました (クエリが複数の行を返す場合にのみ必要です)。
  • SelectCommand の接続文字列を設定するだけにループを変更しました (これを変更して、SelectCommand を新しいものに置き換える必要がある場合があります)。
  • connection.Close() 呼び出しを削除しました。DataAdapter はこれを自動的に行います。

以上です。データベースがオフラインの場合でも速度は低下しますが、テーブル間ですべての行をコピーする必要がないため、少なくともコードはよりシンプルで高速になります。

もう一つ。おそらく、接続文字列で接続のタイムアウトを設定できます。これを下げてみてください。

于 2008-11-20T19:58:26.720 に答える
2

多くの要因が原因で遅くなる可能性があります。実行が遅い SQL ステートメントは何ですか?

これを読んでいる人が sql サーバーを使用している場合、Scott Mitchell が sql サーバーでこれを解決するのに役立つ素晴らしい記事を書いています: 複数のデータベースに対して同じクエリを実行する

于 2008-11-20T19:33:42.557 に答える
1

1つのOracleデータベースで単一のストアドプロシージャを実行し、sprocに他のデータベースを呼び出させてみませんか?これは、リンクされたデータベースを操作するための適切な方法です。

于 2008-11-20T20:34:52.043 に答える
1

これを行うためにレプリケーションを使用してみませんか...ご存知のように、他のデータベースからの新しいデータをプールしている1つの中央データベースで、ダウンすることのないこのデータセットに対してクエリを実行するだけです。

于 2008-11-20T20:42:53.663 に答える
0

このより一般的な質問への回答を得ることに興味があるようです。UI(ASPまたはWinForms)をハングさせずに長時間実行されるタスクを実行するにはどうすればよいですか?

その質問への答えは、複数のスレッドを使用することです。このような長時間実行されるタスクを別のスレッドで実行し、現在の結果を含むページをユーザーに表示します(自動的に更新するかajaxを使用するなど)。( Parallel Extensionsのようなものを使用して)マシンを最大限に活用するために、利用可能なプロセッサごとに凝ったタスクを作成することもできます。ただし、これにより複雑さが大幅に増し、正しく理解するのが難しくなる可能性があります。

.Netでスレッドを使用したことがない場合は、ここにすばらしいチュートリアルがあります(唯一のJon Skeetによる) 。

于 2008-11-20T20:33:16.757 に答える