Почему OracleDataAdapter.Fill () очень медленный? - PullRequest
3 голосов
/ 12 марта 2010

Я использую довольно сложный запрос для извлечения некоторых данных из одной из наших платежных баз данных.

Я столкнулся с проблемой, когда запрос выполняется довольно быстро при выполнении с помощью SQL Developer, но, похоже, не завершается при использовании метода OracleDataAdapter.Fill().

Я пытаюсь прочитать только около 1000 строк, и запрос завершается в SQL Developer примерно за 20 секунд.

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


Вот код, который я использую для выполнения запроса:

using Oracle.DataAccess.Client;

...

public DataTable ExecuteExternalQuery(string connectionString, string providerName, string queryText)
{
    DbConnection connection = null;
    DbCommand selectCommand = null;
    DbDataAdapter adapter = null;

    switch (providerName)
    {
        case "System.Data.OracleClient":
        case "Oracle.DataAccess.Client":
            connection = new OracleConnection(connectionString);
            selectCommand = connection.CreateCommand();
            adapter = new OracleDataAdapter((OracleCommand)selectCommand);
            break;
        ...
    }

    DataTable table = null;
    try
    {
        connection.Open();

        selectCommand.CommandText = queryText;
        selectCommand.CommandTimeout = 300000;
        selectCommand.CommandType = CommandType.Text;

        table = new DataTable("result");
        table.Locale = CultureInfo.CurrentCulture;
        adapter.Fill(table);
    }
    finally
    {
        adapter.Dispose();

        if (connection.State != ConnectionState.Closed)
        {
            connection.Close();
        }
    }

    return table;
}

А вот общая схема используемого мной SQL:

with
  trouble_calls as
  (
    select
      work_order_number,
      account_number,
      date_entered
    from
      work_orders
    where
      date_entered >= sysdate - (15 + 31)  -- Use the index to limit the number of rows scanned
     and
      wo_status not in ('Cancelled')
     and
      wo_type = 'Trouble Call'
  )
select
  account_number,
  work_order_number,
  date_entered
from
  trouble_calls wo
where
  wo.icoms_date >= sysdate - 15
 and
  (
    select
      count(*)
    from
      trouble_calls repeat
    where
      wo.account_number = repeat.account_number
     and
      wo.work_order_number <> repeat.work_order_number
     and
      wo.date_entered - repeat.date_entered between 0 and 30
  ) >= 1

Ответы [ 3 ]

2 голосов
/ 12 марта 2010

Существуют известные различия в производительности между использованием поставщика данных Microsoft для Oracle и собственного поставщика данных Oracle.

Вы пробовали оба?

Чего вы пытаетесь достичь с помощью этого запроса? Забудьте о технических вещах, просто цель всего этого. Возможно, для вашего запроса возможна мелодия.

Вы пытались с помощью профилировщика увидеть, где он застревает?

1 голос
/ 13 октября 2015

Этот код помог мне, попробуйте:

using (OracleConnection conn = new OracleConnection())
{
     OracleCommand comm = new OracleCommand();
     comm.Connection = conn;
     comm.FetchSize = comm.FetchSize * 16;
     comm.CommandText = "select * from some_table";

     try
     {
          conn.Open();
          OracleDataAdapter adap = new OracleDataAdapter(comm);
          System.Data.DataTable dt = new System.Data.DataTable();
          adap.Fill(dt);
     }
     finally
     {
          conn.Close();
     }
}

Трик в строке (попробуйте значения от 8 до 64, чтобы найти лучшее для вашего случая):

comm.FetchSize = comm.FetchSize * 16;

UPDATE:

Вот улучшенный код:

OracleConnection myConnection = new OracleConnection(myConnectionString);
OracleCommand myCommand = new OracleCommand(mySelectQuery, myConnection);
myConnection.Open();
using (OracleDataReader reader = myCommand.ExecuteReader(CommandBehavior.CloseConnection))
{
    // here goes the trick
    // lets get 1000 rows on each round trip
    reader.FetchSize = reader.RowSize * 1000;

    while (reader.Read())
    {
        // reads the records normally
    }
}// close and dispose stuff here

С здесь

1 голос
/ 12 марта 2010

Я думаю, что культура и дата, возвращаемая вашим запросом Oracle, различаются, и именно поэтому приложению требуется много времени для анализа.

...