[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:
$req = fich->bd_select($login, $pass, "select...");
Cette fonction bd_select est la suivante :
Code:
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
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:
$req = fich->bd_select($login, $pass, "select...");
Cette fonction bd_select est la suivante :
Code:
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:
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
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!!! :D :D C'est enorme! :lahola:
Citation:
Envoyé par nematoad
Code:
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:
END { $dbh->disconnect if $dbh }
Ca fait quoi exactement?
Code:
$dbh ||= DBI->connect(...) ;
A quoi correspondent les ||? est ce que ca signifie que $dbh=$dbh OU $dbh = DBI->connect(...); ?
Code:
$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:
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
Re: Optimisation des requetes Oracle/Perl
Citation:
Envoyé par linou
Plusieurs questions...
Code:
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:
$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:
$dbh = $dbh || DBI->connect(...)
Citation:
Envoyé par linou
Code:
$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:
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