Précédent   Forum du club des développeurs et IT Pro > Dotnet > Langages > C#
C# Forum d'entraide sur la programmation C#. Avant de poster -> FAQ C#, Articles C#, Sources C#
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 28/12/2012, 17h22   #1
infosam76
Membre Expert
 
Homme Eric Metz
Développeur informatique
Inscription : avril 2006
Messages : 515
Détails du profil
Informations personnelles :
Nom : Homme Eric Metz
Âge : 36
Localisation : Belgique

Informations professionnelles :
Activité : Développeur informatique
Secteur : Santé

Informations forums :
Inscription : avril 2006
Messages : 515
Points : 1 571
Points : 1 571
Par défaut GetValue assez lent pour récupérer un champ CLOB d'ORACLE

Bonjour,

Dans un programme de statistique, je dois passez en revue une certaine quantité de ligne d'une table Oracle pour effectuer des stats.

Il s'agit d'une ré écriture d'un code VB6 donc j'ai les 2 versions pour comparer les performances.

En gros mon code en c# est le suivant :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
DbCommand cmdBio;
DbDataReader drBio;
 
cmdBio = varGlobals.connection.CreateCommand();
 
cmdBio.CommandText = "SELECT * FROM bio_contenu WHERE numpat="  + NumPat.ToString() + " AND dtebio < '" + varGlobals.dteEnd.AddDays(31).ToShortDateString() + "' AND dtebio >= (SELECT max(dtebio) FROM bio_contenu WHERE numpat=" + NumPat.ToString() + " AND dtebio <= '" + FirstSeanceDate.Value.ToShortDateString() + "') ORDER BY dtebio DESC";
 
cmdBio.CommandType = System.Data.CommandType.Text;
cmdBio.CommandTimeout = 120;
 
drBio = cmdBio.ExecuteReader();
 
string sValeur = ""; 
while (drBio.Read())
{
    sValeur  = drBio.GetValue(drBio.GetOrdinal("compterendu").ToString();
}
Sur 120 enregistrement ce code prend environ 10 secondes contre 2 pour son équivalent VB6

En VB6 c'est ADO qui est utilisé avec un client oracle 11 et une DB oracle 11.

En C# j'utilise les classes style DbProviderFactory car j'ai créé une librairie me permettant de me connecter à plusieurs type de DB. Le provinder utilisé dans ce cas provient de la dll system.data.oracleclient (également via un client oracle 11 sur la même db).

Quelqu'un aurait il une idée pour améliorer les performances ?
infosam76 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2012, 23h16   #2
sisqo60
Membre Expert
 
Avatar de sisqo60
 
Homme
Consultant informatique
Inscription : février 2006
Messages : 727
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Indre et Loire (Centre)

Informations professionnelles :
Activité : Consultant informatique

Informations forums :
Inscription : février 2006
Messages : 727
Points : 1 138
Points : 1 138
Bonjour,

As-tu chronométré les différents bouts de code. Là, tu nous fournis un bout de code standard (je ne me permettrais pas de juger la requête SQL qui ne me semble pas très optimisée, mais je ne connais pas la base de données). En plus tu récupère tes données mais tu n'en fait rien (sauf si tu as supprimé ce bout de code aussi).

Bref, on ne peut pas vraiment t'aider avec ce peu de données.
__________________
Un âne se croit savant parce qu'on le charge de livres (proverbe américain)

N'oubliez pas de avant de
Pas de question techniques par MP, c'est contre la philosophie du forum
sisqo60 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2012, 23h54   #3
infosam76
Membre Expert
 
Homme Eric Metz
Développeur informatique
Inscription : avril 2006
Messages : 515
Détails du profil
Informations personnelles :
Nom : Homme Eric Metz
Âge : 36
Localisation : Belgique

Informations professionnelles :
Activité : Développeur informatique
Secteur : Santé

Informations forums :
Inscription : avril 2006
Messages : 515
Points : 1 571
Points : 1 571
Bonjour et merci pour la réponse rapide.

Effectivement la requête n'est pas vraiment optimisée mais n'est pas de moi et au niveau DB c'est assez conséquent (plus de 1200 tables avec des millions d'enregistrements). Effectivement j'ai retiré une partie du code par soucis de confidentialité.

En fait le champ qu'on récupère dans le CLOB est un XML qui est parser par après. J'ai effectivement chronométré les différentes parties du code pour me rendre compte que c'était au niveau du

Code :
1
2
 
sValeur  = drBio.GetValue(drBio.GetOrdinal("compterendu").ToString();
que cela prenait du temps. Chronométrage effectué avec l'équivalent du code VB et avec le code C#.

J'ai supposé que le problème provenait du fait que je ne passais pas par les objets OracleConnection et CO et j'ai donc effectué un test à la maison (même table mais beaucoup moins d'enregistrements et surtout pas 1500 utilisateurs sur la DB ;-) ). Pour avoir un test concluant je travaille sur la même table (qui contient bcp moins d'enregistrement sur ma DB de test) et au lieu de récupérer 120 enregistrements j'en récupère 1000 en 10 sec avec mon code original. J'ai donc essayé avec les objets de system.data.oracleclient.dll.

Voici le code :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 
OracleConnection con = new OracleConnection("Data Source=SQL_LOCAL;User Id=X;Password=X;");
 
// Connextion à la DB
try
{
   con.Open();
}
catch (Exception ex)
{
   MessageBox.Show(ex.Message, "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
   return;
}
 
try
{
   OracleCommand cmd = con.CreateCommand();
   cmd.CommandText = "SELECT * FROM BIOLOGIE where NumPat <= 115076";
   cmd.CommandType = CommandType.Text;
 
   OracleDataReader odr = cmd.ExecuteReader(); 
 
   System.IO.StreamWriter sw = new System.IO.StreamWriter("d:/TestOracle.txt", false, Encoding.UTF8);
sw.WriteLine("Début : " + DateTime.Now.ToString());
 
   Int32 NbCount = 0;
   string sCompteRendu = "";
   OracleLob myLob = null;
   while (odr.Read())
   {
       myLob = odr.GetOracleLob(odr.GetOrdinal("COMPTERENDU"));
       if(!myLob.IsNull )
          sCompteRendu = myLob.Value.ToString(); 
 
       NbCount++;
    }
 
    sw.WriteLine("Count : " + NbCount.ToString());
    sw.WriteLine("Fin : " + DateTime.Now.ToString());
    sw.Close();
    odr.Close();
    odr.Dispose();
    cmd.Dispose();
}
catch (Exception ex)
{
   MessageBox.Show(ex.Message, "Erreur", MessageBoxButtons.OK,    MessageBoxIcon.Error);
   return;
}
finally
{
   con.Close();
}
 
MessageBox.Show("Fin du traitement", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
Si je retire les 2 lignes :

Code :
1
2
3
 
if(!myLob.IsNull )
   sCompteRendu = myLob.Value.ToString();
Je passe de 11 secondes à 1. J'ai donc l'impression que le problème vient de la conversion de la valeur en string.

Mais je ne vois pas comment amélioré cela. Une idée ?
infosam76 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2012, 21h27   #4
Guulh
Expert Confirmé
 
Avatar de Guulh
 
Homme
Inscription : septembre 2007
Messages : 2 135
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 31
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : septembre 2007
Messages : 2 135
Points : 2 763
Points : 2 763
Hello,

as-tu besoin de convertir en string ? Quel est le type de myLob.Value ?


Par ailleurs, je t'invite à éviter de fabriquer des requêtes par concaténation de chaînes; c'est une faille de sécurité énorme (nommée injection sql), la bonne façon de faire est décrite ici.
__________________
ಠ_ಠ
Guulh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2012, 22h16   #5
infosam76
Membre Expert
 
Homme Eric Metz
Développeur informatique
Inscription : avril 2006
Messages : 515
Détails du profil
Informations personnelles :
Nom : Homme Eric Metz
Âge : 36
Localisation : Belgique

Informations professionnelles :
Activité : Développeur informatique
Secteur : Santé

Informations forums :
Inscription : avril 2006
Messages : 515
Points : 1 571
Points : 1 571
le contenu de la valeur du clob est en fait une arborescence XML qui sera parser par après. Donc je pense que je n'ai pas le choix que de passer par un string.

Par contre merci pour l'info au niveau de la formation des requêtes, ici c'est un programme que je retraduis d'un prog VB6 et dont j'essaie de garder un max de la logique identique même si j'utilise un max les classes.

Mais je vais en profiter pour revoir les requêtes même si c'est pas mon problème principal pour l'instant.
infosam76 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/12/2012, 23h01   #6
infosam76
Membre Expert
 
Homme Eric Metz
Développeur informatique
Inscription : avril 2006
Messages : 515
Détails du profil
Informations personnelles :
Nom : Homme Eric Metz
Âge : 36
Localisation : Belgique

Informations professionnelles :
Activité : Développeur informatique
Secteur : Santé

Informations forums :
Inscription : avril 2006
Messages : 515
Points : 1 571
Points : 1 571
Citation:
Envoyé par Guulh Voir le message
Hello,

as-tu besoin de convertir en string ? Quel est le type de myLob.Value ?


Par ailleurs, je t'invite à éviter de fabriquer des requêtes par concaténation de chaînes; c'est une faille de sécurité énorme (nommée injection sql), la bonne façon de faire est décrite ici.
Tutoriel très intéressant d'autant plus que j'utilise effectivement les DB.... et régulièrement les requêtes paramétrées. Mais je pense que le "régulièrement" va devenir "tous le temps".
infosam76 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/12/2012, 15h26   #7
infosam76
Membre Expert
 
Homme Eric Metz
Développeur informatique
Inscription : avril 2006
Messages : 515
Détails du profil
Informations personnelles :
Nom : Homme Eric Metz
Âge : 36
Localisation : Belgique

Informations professionnelles :
Activité : Développeur informatique
Secteur : Santé

Informations forums :
Inscription : avril 2006
Messages : 515
Points : 1 571
Points : 1 571
J'ai trouvé une solution qui me donne un temps d’exécution proche du VB6, c'est d'utiliser les objets Oracle. Mais hélas je ne sais pas utiliser ma librairie qui me permettait d'utiliser les objets génériques et donc d'être compatible avec plusieurs DB. Dans ce cas-ci cette application ne tournera jamais que sur Oracle mais si quelqu'un à une autre solution je suis preneur.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
try
{
   OracleCommand cmd = con.CreateCommand();
   cmd.CommandText = "SELECT * FROM BIOLOGIE where NumPat <= 115076";
   cmd.CommandType = CommandType.Text;
 
   OracleDataReader odr = cmd.ExecuteReader(); 
 
   string sCompteRendu = "";
   OracleLob myLob = null;
 
   while (odr.Read())
   {
       myLob = odr.GetOracleLob(odr.GetOrdinal("COMPTERENDU"));
 
       if (!myLob.IsNull)
       {
           byte[] b = new byte[myLob.Length];
           myLob.Read(b, 0, (int)myLob.Length);
 
           sCompteRendu = b.ToString();
       }
 
       NbCount++;
   }
 
   odr.Close();
   odr.Dispose();
   cmd.Dispose();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message, "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
    return;
}
infosam76 est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 11/01/2013, 23h28   #8
infosam76
Membre Expert
 
Homme Eric Metz
Développeur informatique
Inscription : avril 2006
Messages : 515
Détails du profil
Informations personnelles :
Nom : Homme Eric Metz
Âge : 36
Localisation : Belgique

Informations professionnelles :
Activité : Développeur informatique
Secteur : Santé

Informations forums :
Inscription : avril 2006
Messages : 515
Points : 1 571
Points : 1 571
Bonjour,

J'ai continuer les tests concernant mon problème. Le temps perdu provient bien du getString sur le clob. J'utilisais la dll trouvée sur le net avec des objets générique (style DBCommand etc.)

J'ai testé la même application en utilisant les objets oracle de la dll Oracle.DataAccess.dll obtenue avec le client oracle 11.2.0. La version de la dll est la 4.112.30. Tout ce passe bien tant que j'utilise l'exécutable compilé sur la machine possédant ce client.

J'ai un autre poste mais qui possède le client 11.1.0 avec Oracle.DataAccess.dll2.111.6.0

Évidement mon application ne trouve pas la dll avec laquelle il a été compilée Il faut savoir que celle-ci fait partie d'une dll que j'ai créé et que celle ci est recopier dans le répertoire de destination de mon application finale.

Ma question est donc comment pouvoir utiliser cette dll obtenue avec le client oracle 11.2.0 sans devoir installer celui-ci sur toute les machines clientes ?

Merci d'avance pour votre aide précieuse;
infosam76 est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 24/01/2013, 20h52   #9
infosam76
Membre Expert
 
Homme Eric Metz
Développeur informatique
Inscription : avril 2006
Messages : 515
Détails du profil
Informations personnelles :
Nom : Homme Eric Metz
Âge : 36
Localisation : Belgique

Informations professionnelles :
Activité : Développeur informatique
Secteur : Santé

Informations forums :
Inscription : avril 2006
Messages : 515
Points : 1 571
Points : 1 571
Bonjour,

Si c'est une dll qui s'installe avec le driver Oracle, je doute que le seul fait de la distribuer avec ton application ne comporte pas de risque. Il faudrait effectué des tests avec différents clients Oracle sur des machines différentes.
__________________
Articles sur les technologies .NET

Une réponse vous a aidé ? utiliser le bouton

Votre problème est résolu ? utiliser le bouton
infosam76 est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 24/01/2013, 21h06   #10
infosam76
Membre Expert
 
Homme Eric Metz
Développeur informatique
Inscription : avril 2006
Messages : 515
Détails du profil
Informations personnelles :
Nom : Homme Eric Metz
Âge : 36
Localisation : Belgique

Informations professionnelles :
Activité : Développeur informatique
Secteur : Santé

Informations forums :
Inscription : avril 2006
Messages : 515
Points : 1 571
Points : 1 571
A part le problème de savoir si le programme trouvera la dll client à tout les coup, le problème de départ étant résolu je clôture cette discussion
infosam76 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 08h24.


 
 
 
 
Partenaires

Hébergement Web