Pregunta

Lo que intento hacer es ejecutar la misma selección SQL en muchas bases de datos Oracle (al menos una docena) y mostrar el resultado en una vista de cuadrícula.

He pirateado algo que funciona pero desafortunadamente es muy lento. Creo que se ve exacerbado por el hecho de que al menos 1 de la docena de bases de datos será invariablemente inalcanzable o de otro modo en estado de error.

Además de ser lento, no puedo evitar pensar que no es la mejor forma de hacerlo, ni muy '.NET'.

He escrito algo similar en el pasado como un bucle simple en PHP que simplemente se conecta a cada db a su vez, ejecuta el sql y escribe otro <tr>, y funciona al menos el doble de rápido, para una consulta determinada . Pero no estoy muy contento con eso, ¡me gustaría mejorar mi conocimiento!

Estoy aprendiendo C # y ASP.NET, así que disculpe el horrible código :)

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

¡Gracias!

ACTUALIZACIÓN: El código SQL varía, para las pruebas he usado consultas muy simples como select sysdate from dual o select name from v$database. En un uso eventual, será mucho más complicado, la idea es que debería poder ejecutar casi cualquier cosa, de ahí el BindData(TextBox1.Text)

ACTUALIZACIÓN: La razón para conectarse a muchas bases de datos desde el código ASP.NET en lugar de un proceso almacenado en uno o todos los dbs, o replicar a un db, es doble. En primer lugar, los dbs en cuestión son réplicas actualizadas con frecuencia de varios entornos de producción similares (por lo general, desarrollo, pruebas y soporte para cada cliente), por lo que cualquier cosa que se haga a los dbs reales debería actualizarse o rehacerse regularmente a medida que se vuelven a cargar de todos modos. En segundo lugar, no sé de antemano qué tipo de consulta podría ejecutarse, este formulario me permite simplemente escribir, p. select count (name) from dbusers contra una docena de bases de datos sin tener que pensar primero en replicar la tabla dbusers en un db maestro.

¿Fue útil?

Solución

Si ejecuta el método DataAdapter.Fill en un objeto DataTable, la tabla se actualizará con los resultados de la consulta. Entonces, en lugar de crear nuevos objetos DataTable y DataSet y luego copiar las DataRows manualmente, simplemente puede agregar filas a la misma tabla.

Pruebe algo como esto (en código C # no probado):

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

Hice los siguientes cambios:

  • Creó un adaptador de datos y le asignó un comando de selección usando su consulta mySQL
  • Dio a la conexión una cadena de conexión vacía
  • Creó un objeto de tabla de datos y eliminó los conjuntos de datos (solo los necesita si su consulta devuelve varias filas)
  • Cambió su bucle para simplemente establecer la cadena de conexión de SelectCommand (puede que tenga que cambiar esto para reemplazar SelectCommand por uno nuevo)
  • Se eliminó la conexión. Llamadas de cierre (). DataAdapter hace esto automáticamente.

Y eso es todo. Si sus bases de datos están fuera de línea, seguirá experimentando ralentizaciones, pero al menos el código es más simple y rápido, ya que no tiene que copiar todas las filas entre sus tablas.

Una cosa más. Probablemente pueda establecer un tiempo de espera para la conexión en la cadena de conexión. Intenta bajar este.

Otros consejos

podría ser una gran cantidad de factores que hacen que sea lento. ¿Cuál es la instrucción sql que se está ejecutando que se ejecuta lentamente?

Si alguien que lee esto está usando el servidor sql, Scott Mitchell acaba de escribir un buen artículo para ayudar a resolver esto en el servidor sql: Ejecutar la misma consulta en múltiples bases de datos

¿Por qué no utilizar la replicación para hacer esto? ... ya sabes, una base de datos central que agrupa datos nuevos de las otras bases de datos y simplemente ejecuta tus consultas sobre este conjunto de datos que nunca va estar abajo.

¿Por qué no ejecutar un único procedimiento almacenado en una base de datos Oracle y hacer que sproc llame a las otras bases de datos? Esta es la forma correcta de trabajar con bases de datos vinculadas.

Parece que puede estar más interesado en obtener una respuesta a esta pregunta más genérica: ¿Cómo puedo ejecutar una tarea de larga ejecución sin colgar la interfaz de usuario (ASP o WinForms)?

La respuesta a esa pregunta es usar múltiples Subprocesos . Realizaría una tarea de larga duración como esta en un hilo separado y le mostraría al usuario una página con los resultados actuales (ya sea que se actualice automáticamente o con ajax, etc.). Incluso puede ser elegante y crear tareas para cada procesador disponible para aprovechar al máximo su máquina (usando algo como Extensiones paralelas ); sin embargo, esto aumenta significativamente la complejidad y puede ser difícil de corregir.

Si no ha trabajado con Threads en .Net, puede encontrar un excelente tutorial aquí (por el único Jon Skeet )

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top