2010-03-12 12 views
3

J'utilise une requête relativement complexe pour extraire des données de l'une de nos bases de données de facturation.Pourquoi OracleDataAdapter.Fill() est très lent?

Je suis confronté à un problème où la requête semble se terminer assez rapidement lors de l'exécution avec SQL Developer, mais ne semble jamais finir lorsque vous utilisez la méthode OracleDataAdapter.Fill(). J'essaie seulement de lire environ 1000 lignes et la requête se termine dans SQL Developer en 20 secondes environ.

Qu'est-ce qui pourrait causer de telles différences de performance? J'ai des tonnes d'autres requêtes qui s'exécutent rapidement en utilisant la même fonction.


Voici le code que je utilise pour exécuter la requête:

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

Et voici les grandes lignes de SQL J'utilise:

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

J'ai rencontré des problèmes similaires avec SQL Server mais aucune résolution satisfaisante. Si vous pouvez exécuter une trace de paquet ou une trace d'application pour comparer les deux requêtes, cela pourrait éclairer le sujet. – dsolimano

Répondre

2

Il y a les différences de performances connues entre l'utilisation du fournisseur de données Microsoft pour Oracle et le fournisseur de données Oracle natif.

Avez-vous essayé les deux?

Qu'essayez-vous d'accomplir avec cette requête? Oubliez les trucs techniques, juste l'objectif de tout cela. Peut-être y at-il un morceau possible pour votre requête.

Avez-vous essayé avec un profiler pour voir où il se coince?

+0

J'utilise Oracle.DataAccess.dll d'Oracle –

+1

En fait, 'Systm.Data.OracleClient' a été déprécié dans .NET 4 - http://msdn.microsoft.com/fr-fr/library/system.data .oracleclient (VS.100) .aspx –

+0

Donc, en haut, j'ai 'using Oracle.DataAccess.Client;' –

1

Je pense que la culture et la date renvoyées par votre requête Oracle sont différentes et c'est là que l'application prend beaucoup de temps à analyser.

+0

Frapper le même serveur de base de données avec le même code en utilisant d'autres requêtes s'exécute très rapidement. J'ai laissé cette requête de 20 secondes s'exécuter pendant la nuit. Je vais regarder dans ce tho ... –

+0

Pas de dés. La suppression de l'appel 'table.Locale' n'a eu aucun effet. –

1

Ce code m'a aidé, essayer:

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

Le Trik est en ligne (essayez les valeurs de 8 à 64 pour trouver le meilleur pour votre cas):

comm.FetchSize = comm.FetchSize * 16; 

MISE À JOUR:

Voici un code amélioré:

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 

De here

+1

Explication est ici: http://metekarar.blogspot.com/2013/04/performance-improvement-for-odpnet.html –