2010-03-12 5 views
3

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

Я столкнулся с проблемой, когда запрос, по-видимому, выполняется довольно быстро при выполнении 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 
+0

У меня были подобные проблемы с SQL Server, но без удовлетворительного разрешения. Если вы можете запустить трассировку пакетов или трассировку приложения для сравнения двух запросов, это может пролить свет на вопрос. – dsolimano

ответ

2

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

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

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

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

+0

Я использую Oracle.DataAccess.dll от Oracle –

+1

Фактически, 'Systm.Data.OracleClient' устарел в .NET 4 - http://msdn.microsoft.com/en-us/library/system.data .oracleclient (VS.100) .aspx –

+0

Итак, наверху, я использую Oracle.DataAccess.Client; ' –

1

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

+0

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

+0

Нет кубиков. Удаление вызова «table.Locale» не повлияло. –

1

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

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 

От here

+1

Пояснение: http://metekarar.blogspot.com/2013/04/performance-improvement-for-odpnet.html –

Смежные вопросы