хороший способ для запроса многих баз данных в ASP.NET - PullRequest
0 голосов
/ 20 ноября 2008

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

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

Помимо того, что я медленный, я не могу не думать, что это не самый лучший способ сделать это и не очень похожий на .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 в главную базу данных.

Ответы [ 5 ]

3 голосов
/ 20 ноября 2008

Если вы запустите метод 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 новой)
  • Удалено соединение. Закрыть () вызовы. DataAdapter делает это автоматически.

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

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

2 голосов
/ 20 ноября 2008

может быть много факторов, заставляющих это быть медленным. Что за SQL-оператор выполняется медленно?

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

1 голос
/ 20 ноября 2008

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

1 голос
/ 20 ноября 2008

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

0 голосов
/ 20 ноября 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...