IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SGBD Perl Discussion :

[sgbd]Optimisation des requetes Oracle/Perl


Sujet :

SGBD Perl

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 171
    Points : 70
    Points
    70
    Par défaut [sgbd]Optimisation des requetes Oracle/Perl
    Bonjour a tous,

    Je travaille sur une appli client/serveur (Perl / Oracle) et mon code est tres lent et je viens de me rendre compte de quelque chose...

    Tout d'abord, j'ai essayé d'afficher ma page sans aucune requete sur la base de données. L'affichage est tres rapide.

    Lorsque je remet toutes les requetes, l'affichage devient super long. Mais vous allez me dire q cest normal, ce que je comprend tout a fait.

    Par contre, j'ai étudié comment été faites les requetes. A chaque requete, on fait un appel a la fonction bd_select :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $req = fich->bd_select($login, $pass, "select...");
    Cette fonction bd_select est la suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    sub bd_select{
      my $login = $_[1];
      my $pass = $_[2];
      $dbh = DBI->connect(...) ;
      my $sql = $_[3];
      if ($dbh) {    
        $sth = $dbh->prepare($sql) or die "Can't prepare statement : ", DBI::errstr;
        $rc = $sth->execute or die "Can't execute statement : ", DBI::errstr;
        my $array = $sth->fetchall_arrayref;
        $sth->finish;
        $dbh->disconnect();
        return $array;
      }
     else {
        return ("error");
      }
    }
    Cela signifie que pour la moindre requete, on ouvre la connexion a la base Oracle, on fait la requete et on referme la connexion.

    Est ce qu'il ne serait pas mieux d'ouvrir la connexion en debut de script, faire les differentes requetes dont on a besoin, et refermer la connexion en fin de script.
    Je procede comme ca avec php/Mysql, je ne sais pas si c'est faisable dans le cas de Perl/Oracle, mais je pense que si ca marchait, on gagnerait un temps considerable puisqu'il me semble que la connexion a une base Oracle est une opération couteuse en temps.

    Qu'en pensez vous?

    Merci a tous

  2. #2
    Membre chevronné
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2003
    Messages
    1 563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Février 2003
    Messages : 1 563
    Points : 2 003
    Points
    2 003
    Par défaut
    OUI, il vaut mieux n'ouvrir qu'une session à ta BDD lorsque le programme tourne. A mon avis, pas besoin de tourner autour du pot, c'est le fait de se connecter à chaque requète qui fait perdre un temps précieux à ton programme.

    Par contre, ce que tu peux faire, en plus de ne gérer plus qu'une seule connexion, c'est d'utiliser la méthode ping() du module DBI.pm (ou celui d'Oracle). Elle renvoie 1 si la connexion à la BDD est toujours active, 0 si déconnectée.

    Via la méthode ping(), tu pourras toujours rouvrir une connexion si jamais celle-ci est tombée

  3. #3
    Membre actif
    Inscrit en
    Février 2005
    Messages
    167
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 167
    Points : 203
    Points
    203
    Par défaut Re: Optimisation des requetes Oracle/Perl
    Citation Envoyé par linou
    Lorsque je remet toutes les requetes, l'affichage devient super long. Mais vous allez me dire q cest normal, ce que je comprend tout a fait.

    Par contre, j'ai étudié comment été faites les requetes. A chaque requete, on fait un appel a la fonction bd_select :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $req = fich->bd_select($login, $pass, "select...");
    Cette fonction bd_select est la suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    sub bd_select{
      my $login = $_[1];
      my $pass = $_[2];
      $dbh = DBI->connect(...) ;
      my $sql = $_[3];
      if ($dbh) {    
        $sth = $dbh->prepare($sql) or die "Can't prepare statement : ", DBI::errstr;
        $rc = $sth->execute or die "Can't execute statement : ", DBI::errstr;
        my $array = $sth->fetchall_arrayref;
        $sth->finish;
        $dbh->disconnect();
        return $array;
      }
     else {
        return ("error");
      }
    }
    Cela signifie que pour la moindre requete, on ouvre la connexion a la base Oracle, on fait la requete et on referme la connexion.
    La solution la plus simple consiste à modifier ton script afin de garder la connexion ouvert, et mettre en cache les requêtes déjà préparées :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    { # scope pour bd_select
    my $dbh;
    END { $dbh->disconnect if $dbh }
     
    sub bd_select{
      my $login = $_[1];
      my $pass = $_[2];
      $dbh ||= DBI->connect(...) ;
      my $sql = $_[3];
      if ($dbh) {    
        $sth = $dbh->prepare_cached($sql) or die "Can't prepare statement\n$sqsl\nerr : ", DBI::errstr;
        $rc = $sth->execute or die "Can't execute statement : ", DBI::errstr;
        my $array = $sth->fetchall_arrayref;
        $sth->finish;
        return $array;
      }
     else {
        return undef;
      }
    }
    } # bd_select
    Aussi, il est plus utile de renvoyer undef au lieu de la chaîne "error" : le code pour écrire les tests est plus facile à écrire.

    N

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 171
    Points : 70
    Points
    70
    Par défaut Re: Optimisation des requetes Oracle/Perl
    Citation Envoyé par nematoad
    La solution la plus simple consiste à modifier ton script afin de garder la connexion ouvert
    Ca je lai fait, jai sorti le DBI->connect(...) de mon bd_select et je lai mis dans une nouvelle fonction que j'appelle au debut de mon script.
    J'ai mis des "warn localtime" pour faire le suivi et je passe deja d'un temps moyen d'execeution de 28,4 secondes a 2,5 sec!!! C'est enorme!

    Citation Envoyé par nematoad
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    { # scope pour bd_select
    my $dbh;
    END { $dbh->disconnect if $dbh }
     
    sub bd_select{
      my $login = $_[1];
      my $pass = $_[2];
      $dbh ||= DBI->connect(...) ;
      my $sql = $_[3];
      if ($dbh) {    
        $sth = $dbh->prepare_cached($sql) or die "Can't prepare statement\n$sqsl\nerr : ", DBI::errstr;
        $rc = $sth->execute or die "Can't execute statement : ", DBI::errstr;
        my $array = $sth->fetchall_arrayref;
        $sth->finish;
        return $array;
      }
     else {
        return undef;
      }
    }
    } # bd_select
    Plusieurs questions...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    END { $dbh->disconnect if $dbh }
    Ca fait quoi exactement?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      $dbh ||= DBI->connect(...) ;
    A quoi correspondent les ||? est ce que ca signifie que $dbh=$dbh OU $dbh = DBI->connect(...); ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
       $sth = $dbh->prepare_cached($sql)
    Ca change quoi par rapport au fait de juste mettre prepare?

    Et l'autre problème, cest que bd_select est dans un package donc si j'utilise ton code, comment quest ce quil faut que je mette ou?
    Je suppose que je laisse le bd_select dans le package, mais ces lignes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    my $dbh;
    END { $dbh->disconnect if $dbh }
    elles vont ou, dans le package ou dans le code de ma page?

    Merci deja pour les reponses

  5. #5
    Membre actif
    Inscrit en
    Février 2005
    Messages
    167
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 167
    Points : 203
    Points
    203
    Par défaut Re: Optimisation des requetes Oracle/Perl
    Citation Envoyé par linou
    Plusieurs questions...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    END { $dbh->disconnect if $dbh }
    Ca fait quoi exactement?
    A la fin de l'execution de ton script, la base de données sera déconnectée proprement, peu importe comment ça se termine (fin, exit, die). Enfin, si ça se termine à cause d'un reboot intempestif de la machine, ou d'un segfault, kill, etc. etc, alors non, mais tu vois l'idée. Si tu as des notions de C, il faut penser à atexit().

    Citation Envoyé par linou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      $dbh ||= DBI->connect(...) ;
    A quoi correspondent les ||?
    La premiere fois qu'on passes dessus, $dbh est undef, et donc on execute le DBI->connect. La prochaine fois il ne se passe rien. Pour le voir autrement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $dbh = $dbh || DBI->connect(...)

    Citation Envoyé par linou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
       $sth = $dbh->prepare_cached($sql)
    Ca change quoi par rapport au fait de juste mettre prepare?
    Ça fait que s'il a déjà rencontré la requête dans le $sql, il peut réutiliser certains trucs qu'il a fait la première fois (comme le plan d'execution).

    Citation Envoyé par linou
    Et l'autre problème, cest que bd_select est dans un package donc si j'utilise ton code, comment quest ce quil faut que je mette ou?
    Je suppose que je laisse le bd_select dans le package, mais ces lignes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    my $dbh;
    END { $dbh->disconnect if $dbh }
    elles vont ou, dans le package ou dans le code de ma page?
    Tu laisses avec, dans le scope { ... }

    N

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 171
    Points : 70
    Points
    70
    Par défaut
    Merci!
    J'avais cherché dans la doc donc finalement, j'avais quasiment toute les reponses.

    Mais j'ai une erreur :

    Voila le code que j'ai dans mon package :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    { # scope pour bd_select
    my $dbh;
    END { $dbh->disconnect if $dbh } 
     
    sub bd_select{
      my $login = $_[1];
      my $pass = $_[2];
      $dbh ||= DBI->connect('Dbi:Oracle:',$login,$pass,{
    						  PrintError => 1, # warn() on errors
    						  RaiseError => 0, # don't die on error
    						  AutoCommit => 0, # don't commit executes immediately
    						 }) ;#or die "ERROR : couldn't connect to database ", DBI::errstr;
      my $sql = $_[3];
      if ($dbh) {
     
        $sth = $dbh->prepare_cached($sql) or die "Can't prepare statement : ", DBI::errstr;
     
        $rc = $sth->execute or die "Can't execute statement : ", DBI::errstr;
        my $array = $sth->fetchall_arrayref;
        $sth->finish;
        $dbh->disconnect();
        return $array;
      } else {
        return undef;
      }
    }
    }# bd_select
    Et l'erreur:
    DBD::Oracle::db_prepare_cached failed: ERROR Database disconnected at Test.pm line 102.
    Can't prepare statement : ERROR Database Disconnected at Test.pm line 102
    Et bien sur, la ligne 102 est celle ou il y a prepare_cached...

    [edit : c'est bon, jai trouve... J'avais laissé le disconnect... Mais ce que je ne comprend pas, cest pourquoi la connexion n'a pas été retablie grace a $dbh ||= DBI->connect(...)?
    Ca veut dire que sil y a deceonnexion, il ny a pas reconnexion...]

  7. #7
    Membre actif
    Inscrit en
    Février 2005
    Messages
    167
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 167
    Points : 203
    Points
    203
    Par défaut
    Citation Envoyé par linou
    [edit : c'est bon, jai trouve... J'avais laissé le disconnect... Mais ce que je ne comprend pas, cest pourquoi la connexion n'a pas été retablie grace a $dbh ||= DBI->connect(...)?
    Ca veut dire que sil y a deceonnexion, il ny a pas reconnexion...]
    Parce que $dbh pointe sur un objet valable (pas undef), bien qui l'objet en question pointe sur une base qui a été déconnecté.

    Remarque, je t'ai peut-être induit en erreur, du moins, je te fais faire des choses plus compliquées que nécessaire. De nos jours, les versions de DBI contien une méthode connect_cached, qui joue un peu le même rôle que prepare_cached. Ça connecte si c'est pas connecté, et ça te renvoie le handle déjà ouvert la prochaine fois que tu l'appelles. Je devrais prendre l'habitude moi-même, je suppose...

    D'autant plus que si la connexion tombe plus tard, la fois suivant, connect_cached va tenter de rétablir la connexion automatiquement. Donc tu gagnes à tout les coups.

    N

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 171
    Points : 70
    Points
    70
    Par défaut
    et bien il va falloir que je me renseigne sur le role de la fonction connect_cached qui a l air de faire des choses pas mal
    Merci pour ton aide deja!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Optimiser des requetes
    Par lodan dans le forum Requêtes
    Réponses: 10
    Dernier message: 01/04/2009, 12h29
  2. Ajax & Optimisation des requetes HTTP
    Par Spir dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 18/09/2008, 12h27
  3. Optimisation des requetes SQL
    Par elharet dans le forum SQL
    Réponses: 3
    Dernier message: 14/11/2007, 22h26
  4. Optimisation de requete oracle
    Par Mehdilis dans le forum Oracle
    Réponses: 4
    Dernier message: 18/12/2006, 14h42
  5. Optimisation des requetes
    Par bifidus dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 06/10/2003, 12h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo