Вопрос

Я пытаюсь запустить один и тот же SQL-выбор во многих базах данных Oracle (по крайней мере, дюжине) и отобразить выходные данные в Gridview.

Я взломал кое-что, что работает, но, к сожалению, это очень медленно.Я думаю, что ситуация усугубляется тем фактом, что по крайней мере одна из дюжины баз данных всегда будет недоступна или иным образом находится в состоянии ошибки.

Помимо того, что я медленный, я не могу избавиться от мысли, что это не лучший способ сделать это и не очень похоже на «.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 dual или select name from v$database.В конечном итоге это будет намного сложнее, идея в том, что я смогу запускать практически все, отсюда и BindData(TextBox1.Text)

ОБНОВЛЯТЬ:Причина подключения ко многим базам данных из кода ASP.NET, а не хранимой процедуры в одной или всех базах данных или репликации в одну базу данных, двояка.Во-первых, рассматриваемые базы данных являются часто обновляемыми копиями нескольких аналогичных производственных сред (обычно это разработка, тестирование и поддержка для каждого клиента), поэтому все, что делается с реальными базами данных, должно будет регулярно обновляться или переделываться, поскольку они в любом случае перезагружаются.Во-вторых, я заранее не знаю, какой запрос может быть выполнен, эта форма позволяет мне просто ввести, например. select count (name) from dbusers против дюжины баз данных без необходимости предварительно думать о репликации таблицы dbusers в главную базу данных.

Это было полезно?

Решение

Если вы запустите метод DataAdapter.Fill для объекта DataTable, таблица будет обновлена ​​с учетом результатов запроса.Таким образом, вместо того, чтобы создавать новые объекты 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.
  • Дал соединению пустую строку подключения
  • Создал объект таблицы данных и удалил наборы данных (они нужны вам только в том случае, если ваш запрос возвращает несколько строк).
  • Изменен цикл, чтобы просто установить строку подключения SelectCommand (возможно, вам придется изменить это, заменив SelectCommand новым)
  • Удалены вызовы Connection.Close().DataAdapter делает это автоматически.

Вот и все.Если ваши базы данных находятся в автономном режиме, замедление работы все равно будет наблюдаться, но, по крайней мере, код станет проще и быстрее, поскольку вам не придется копировать все строки между таблицами.

Еще кое-что.Вероятно, вы можете установить тайм-аут соединения в строке подключения.Попробуйте снизить этот показатель.

Другие советы

может быть много факторов, вызывающих его медленную работу.Какой оператор sql выполняется медленно?

Если кто-то, читающий это, использует sql-сервер, Скотт Митчелл только что написал хорошую статью, которая поможет решить эту проблему на sql-сервере: Выполнение одного и того же запроса к нескольким базам данных

Почему бы не использовать для этого репликацию... вы знаете, одну центральную базу данных, которая собирает новые данные из других баз данных и просто выполняет ваши запросы к этому набору данных, который никогда будет вниз.

Почему бы не запустить одну хранимую процедуру в одной базе данных Oracle и не позволить процедуре вызывать другие базы данных?Это правильный способ работы со связанными базами данных.

Похоже, вас больше интересует ответ на более общий вопрос: Как я могу выполнить длительную задачу без зависания пользовательского интерфейса (ASP или WinForms)?

Ответ на этот вопрос — использовать несколько Потоки.Я бы выполнил подобную длительную задачу в отдельном потоке и показал пользователю страницу с текущими результатами (либо автоматическое обновление, либо с помощью ajax и т. д.).Вы даже можете проявить фантазию и создать задачи для каждого доступного процессора, чтобы максимально эффективно использовать возможности вашей машины (используя что-то вроде Параллельные расширения);однако это значительно увеличивает сложность, и может быть трудно сделать все правильно.

Если вы еще не работали с потоками в .Net, можно найти отличный учебник. здесь (одним и единственным Джон Скит)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top