在 ASP.NET 中查询多个数据库的好方法

发布于 2024-07-09 08:26:25 字数 3556 浏览 12 评论 0原文

我想做的是在许多 Oracle 数据库(至少十几个)上运行相同的 SQL 选择,并在 Gridview 中显示输出。

我已经拼凑了一些有用的东西,但不幸的是它非常慢。 我认为,十几个数据库中至少有一个总是无法访问或处于错误状态,这一事实加剧了这一情况。

除了速度慢之外,我不禁认为这不是最好的方法,也不像“.NET”。

我过去在 PHP 中写过类似的简单循环,它只是依次连接到每个数据库,运行 sql 并编写另一个 ,它的运行速度至少是原来的两倍,对于给定的查询。 但我对此并不满意,我想提高我的知识!

我正在学习 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。 在最终使用中,它会更加复杂,我的想法是我应该能够运行几乎任何东西,因此 BindData(TextBox1.Text)

更新: 从ASP.NET 代码而不是一个或所有数据库上的存储过程,或者复制到一个数据库,是双重的。 首先,所讨论的数据库是几个类似生产环境(通常是每个客户端的开发、测试和支持)的频繁更新的副本,因此对实际数据库所做的任何操作都必须定期更新或重做,因为无论如何都会重新加载它们。 其次,我事先不知道可能运行哪种查询,这种形式让我只需针对十几个数据库输入例如 select count (name) from dbusers ,而不必首先考虑复制dbusers 表到主数据库。

What I'm trying to do is run the same SQL select on many Oracle databases (at least a dozen), and display the output in a Gridview.

I've hacked together something that works but unfortunately it's very slow. I think its exacerbated by the fact that at least 1 of the dozen databases will invariably be unreachable or otherwise in an error state.

As well as being slow I can't help thinking it's not the best way of doing it, nor very '.NET' like.

I've written something similar in the past as a simple loop in PHP that just connects to each db in turn, runs the sql and writes another <tr>, and it works at least twice as fast, for a given query. But I'm not really happy with that, I'd like to improve my knowledge!

I'm learning C# and ASP.NET so please excuse the horrible code :)

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

Thanks!

UPDATE: The SQL code varies, for testing I have used very simple queries such as select sysdate from dual or select name from v$database. In eventual use, it will be much more complicated, the idea is that I should be able to run pretty much anything, hence the BindData(TextBox1.Text)

UPDATE: The reason for connecting to many databases from the ASP.NET code rather than a stored proc on one or all dbs, or replicating to one db, is twofold. Firstly, the dbs in question are frequently updated replicas of several similar production environments (typically development, testing and support for each client), so anything done to the actual dbs would have to be updated or redone regularly as they are reloaded anyway. Secondly, I don't know in advance what kind of query might be run, this form lets me just type e.g. select count (name) from dbusers against a dozen databases without having to first think about replicating the dbusers table to a master db.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

暖风昔人 2024-07-16 08:26:25

如果对 DataTable 对象运行 DataAdapter.Fill 方法,该表将使用查询结果进行更新。 因此,您无需创建新的 DataTable 和 DataSet 对象,然后手动复制 DataRow,只需将行添加到同一个表中即可。

尝试这样的操作(在未经测试的 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 查询为其分配一个选择命令
  • 为连接提供一个空连接字符串
  • 创建一个数据表对象并删除数据集(您仅当您的查询返回多行时才需要它们)
  • 将循环更改为仅设置 SelectCommand 的连接字符串(您可能必须将其更改为用新字符串替换 SelectCommand)
  • 删除了 connection.Close() 调用。 DataAdapter 自动执行此操作。

就是这样。 如果您的数据库处于离线状态,您仍然会遇到速度减慢的情况,但至少代码更简单、更快,因为您不必复制表之间的所有行。

还有一件事。 您可以在连接字符串中设置连接超时。 尝试降低这一点。

If you run the DataAdapter.Fill method on a DataTable object the table will be updated with the results from the query. So instead of creating new DataTable and DataSet objects and then copying the DataRows manually you can just add rows to the same table.

Try something like this (in untested C# code):

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

I did the following changes:

  • Created one data adapter and assigned it a select command using your mySQL query
  • Gave the connection an empty connection string
  • Created a data table object and removed the data sets (you only need them if your query returns several rows)
  • Changed you loop to just set the connection string of the SelectCommand (you may have to change this to replacing the SelectCommand with a new one)
  • Removed the connection.Close() calls. The DataAdapter does this automatically.

And thats it. If your databases are offline you will still experience slowdowns, but at least the code is simpler and faster since you don't have to copy all the rows between your tables.

One more thing. You can probably set a timeout for the connection in the connection string. Try to lower this one.

莫相离 2024-07-16 08:26:25

可能有很多因素导致它变慢。 正在执行的 sql 语句运行缓慢的原因是什么?

如果有人阅读本文正在使用 sql server,Scott Mitchell 刚刚写了一篇很好的文章来帮助解决 sql server 中的问题: 对多个数据库运行相同的查询

could be a lot of factors causing it to be slow. What's the sql statement being executed that's running slow?

If anyone reading this is using sql server, Scott Mitchell just wrote a nice article to help solve this in sql server: Running the Same Query Against Multiple Databases

红ご颜醉 2024-07-16 08:26:25

为什么不使用复制来做到这一点......你知道,一个中央数据库正在汇集来自其他数据库的新数据,并且只需对这组数据执行查询,而这组数据永远不会宕机。

Why not use replication to do this...you know, one central database which is pooling for new data from the other databases and just execute your queries over this set of data which is never going to be down.

生寂 2024-07-16 08:26:25

为什么不在一个 Oracle 数据库上运行单个存储过程,并让存储过程调用其他数据库呢? 这是使用链接数据库的正确方法。

Why not run a single stored procedure on one oracle database, and have the sproc call the other databases? This is the proper way to work with linked databases.

紫竹語嫣☆ 2024-07-16 08:26:25

听起来您可能更有兴趣获得这个更通用问题的答案:如何在不挂起 UI 的情况下执行长时间运行的任务(ASP 或 WinForms)?

该问题的答案是使用多个 线程 。 我将在单独的线程上执行这样的长时间运行任务,并向用户显示包含当前结果的页面(自动刷新或使用 ajax 等)。 您甚至可以为每个可用处理器创建任务,以充分利用您的计算机(使用类似 并行扩展); 然而,这显着增加了复杂性并且很难做到正确。

如果您还没有使用过 .Net 中的线程,可以在此处(由唯一的乔恩·斯基特

It sounds like you may be more interested in getting an answer to this more generic question: How can I execute a long running task without hanging the UI (ASP or WinForms)?

The answer to that question is to use multiple Threads. I would perform a long running task like this on a separate thread and show the user a page with the current results (either refreshing automatically or with ajax, etc). You can even get fancy and create tasks for each available processor to get the most out of your machine (using something like the Parallel Extensions); however this increases the complexity significantly and can be hard to get right.

If you haven't worked with Threads in .Net a great tutorial can be found here (by the one and only Jon Skeet)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文