Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
Pages : 1
#1 Re : C et C++ » utilisation de PQsetSingleRowMode » 18/09/2013 09:23:10
Bonjour,
Je reprends un peu le fil de la conversation, j'ai toujours des problèmes de performances. J'ai remarqué des différences notables entre Oracle et PostGre. Sur une table de plusieurs millions d'enregistrements, je remarque une différence notable entre les requêtes suivantes :
Oracle (via oci.dll, 8 sec, avec un forçage pour l'utilisation de l'index)
SELECT /*+ index_asc(F60 if60a) */ F60.*, ROWID FROM F60 WHERE f60type>' ' ORDER BY f60type, f60n_pers
PostGre (via libpq, 30sec)
BEGIN
DECLARE F60c1 CURSOR WITH HOLD FOR SELECT F60.*, OID FROM F60 WHERE f60type>' ' ORDER BY f60type, f60n_pers
FETCH 1 FROM F60c1
COMMIT
Dans la librairie oci.dll, on peut itérer sur un résultat via des fonctions spécifiques (OCIfetch), c'est pourquoi je n'utilise pas de curseur en Oracle.
VACUUM ANALYSE effectué sur toute la table.
Pour Postgre, la requête est exécutée lors de l'appel au premier FETCH, est-ce que le fait de passer par un curseur ralentit les performances ?
Est-ce que je dois me tourner vers la configuration des indexs? Optimiser la configuration de la base Postgre?
Ci-dessous la configuration de mes indexs :
Oracle
-INDEX- -uniqueness- -status- -type- -temporary- -partitioned- -join index- -columns-
IF60A NONUNIQUE VALID NORMAL N NO NO F60TYPE, F60N_PERS
IF60B NONUNIQUE VALID NORMAL N NO NO F60TYPE, F60ATOME
PostGre
CREATE INDEX if60a
ON f60
USING btree
(f60type COLLATE pg_catalog."default", f60n_pers COLLATE pg_catalog."default");
Cordialement,
Thomas
#2 Re : C et C++ » utilisation de PQsetSingleRowMode » 12/09/2013 23:35:57
Je ne connais pas VACUUM ANALYZE, la version est la 9.2
#3 Re : C et C++ » utilisation de PQsetSingleRowMode » 12/09/2013 23:26:33
Bonsoir,
4. Je vérifierai demain les indexs, ils sont normalement présents.
Pour le 5. Le gain est de pouvoir récupérer les 50 premières lignes et les afficher dans une IHM par exemple.
J'éditerai demain ce message pour répondre aux autres questions.
Merci beaucoup !!
Thomas
#4 Re : C et C++ » utilisation de PQsetSingleRowMode » 12/09/2013 11:31:08
Concernant mon problème de performance... J'ai monitoré mon application et j'ai découvert ceci :
PQExec(conn, "DECLARE F60c3 CURSOR FOR SELECT OID, F60.* FROM F60 WHERE F60TYPE>$1 ORDER BY F60TYPE, F60N_PERS");
Ce select contient environ 3 000 000 d'enregistrements.
Si je fais un :
PQExec(conn, "FETCH FIRST FROM F60c3");
PQExec ne rend la main que 15 secondes plus tard...
Si quelqu'un a une explication je suis preneur
EDIT :
Je pense que je dois utilisé un LIMIT afin de limiter les résultats de la première exécution du fetch. (exemple LIMIT 50)
Pour passer aux 50 enregistrements suivant je devrais donc associer OFFSET et LIMIT. Le probleme c'est que je ne peux pas redeclarer mon curseur sans perdre le curseur...
Il me faudrait donc un retour de la part de PQExec qui me dise si je suis en fin de table ou seulement à la fin de l'exécution contraint par LIMIT.
Existe-t-il un tel retour?
Thomas.
#5 Re : C et C++ » utilisation de PQsetSingleRowMode » 12/09/2013 09:43:12
Bonjour Guillaume,
Merci pour tes réponses.
1. Je ne comprends toujours pas pourquoi je peux déclarer un curseur paramétré mais pas un curseur générique.
2. La fonction Oracle ci-dessus permet de définir un mode de fonctionnement spéciale à la fonction (OCIStmtFetch()). Si celle-ci "fetch" les lignes une par une (FETCH NEXT), alors le nombre de communication entre le client et le serveur sera égal aux nombre de lignes. Le mode PREFECTH de Oracle permet de définir un nombre de ligne à fetché en mémoire pour limiter ce nombre de communication.
3. Autant pour moi, j'utilisais la combinaison BEGIN/DO QUERY/COMMIT/DO QUERY/COMMIT/DO OTHER QUERY/.../END. Sans les COMMIT je n'ai plus de désallocation du curseur. Par contre j'ai pas mal de problèmes de performances... Comment les communications avec le serveur évolue dans une transaction ?
Cordialement,
Thomas
#6 Re : C et C++ » utilisation de PQsetSingleRowMode » 11/09/2013 23:30:51
Bonsoir,
Personne pour répondre ?
Un autre problème...
Quand on execute un "DELETE FROM table1 WHERE CURRENT OF curTable;"
Pourquoi le curseur est désalloué?
Cordialement,
Thomas
#7 Re : C et C++ » utilisation de PQsetSingleRowMode » 06/09/2013 15:54:06
Bonjour
Avec quelques difficultés à cause de la gestion des transactions, j'ai finalement réimplémenté une version avec curseurs...
Je ne trouve pas beaucoup d'informations sur internet pour les deux questions suivantes :
1. Peut-on utiliser des curseurs génériques avec libpq.dll ?
Le code suivant fonctionne :
PQexec(conn, "BEGIN");
PQexec(conn, "DECLARE mycur CURSOR FOR [...]");
PQexec(conn, "END");
Mais celui-ci ne fonctionne pas :
PQexec(conn, "BEGIN");
PQexec(conn, "DECLARE mycur REFCURSOR");
PQexec(conn, "END");
2. Existe-t-il un équivalent au mode prefetch de la lib oci.dll pour libpq.dll ?
OCIAttrSet((dvoid *) requete->stmt, OCI_HTYPE_STMT, (dvoid *) &nb_ligne, (ub4) 0, OCI_ATTR_PREFETCH_ROWS,errhp)
Cordialement,
Thomas
#8 Re : C et C++ » utilisation de PQsetSingleRowMode » 30/08/2013 10:50:09
Bonjour,
Premièrement merci de répondre si rapidement et de façon si pertinente ! En effet j'avais commencé l'implémentation de mon ensemble de fonctions avec un curseur (Je cherche bien à me déplacer dans un ensemble de résultats). Chose que j'ai vite abandonnée pour des questions de performance.
Je pense qu'il est temps que j'explique un peu plus le contexte...
J'ai une application qui intéragit avec une base Oracle via une DLL (surcouche de l'API OCI). Je suis en train de migrer cette DLL vers PostgreSQL. La contrainte est triple :
* Garder les mêmes signatures de fonctions pour les deux DLLs (Utilisation transparente pour l'application)
* Avoir des performances semblables
* Avoir un comportement iso-fonctionnel.
J'ai notamment dans mon application trois fonctions importantes :
LitRecherche : en gros un select dans une requête préparée (avec stockage de la requête dans une structure particulière, si la requête suivante possède des paramètres semblables, -> on effectue seulement le binding)
LitSuivant : permet d'itérer sur les enregistrments
LitChamp : permet de lire la valeur d'un attribut particulier de l'enregistrement
Mon souci est de faire un PQsendQuery sur un deuxième LitRecherche (il me jette en me disant qu'une requête est déjà en cours) sans avoir "flusher" le resultat de la précédente.
La solution du curseur paraît en effet beaucoup plus adaptée d'un point de vue théorique, mais les performances ne sont malheureusmeent pas au rdv ! De plus l'utilisation des transactions avec les curseurs semble ralentir les traitements.
Pour information l'API OCI d'Oracle permet d'allouer un 'handle' sur une requête indépendamment de la connexion utilisée alors que l'API libpq via PQsendQuery (seul le mode asynchrone fonctionne avec RowByRow mode) récupere le résultat d'une requête avec pour seul paramètre le PGconn.
PS : Le bon point pour l'instant est que même avec cette longue boucle (cf. premier post), j'arrive à être compétitif face à Oracle. Mais ce n'est pas super propre et je ne connaît pas encore le comportement sur des tables ayant des millions d'enregistrements... tests en cours...
Cordialement,
Thomas
#9 Re : C et C++ » utilisation de PQsetSingleRowMode » 29/08/2013 11:28:01
Bonjour,
Loin de moi la volonté de critiquer... Mais c'est bien dommage !
Pour moi le rowbyrow mode a été implémenté pour décharger la mémoire vive du client en traitant un à un les enregistrements renvoyés par le serveur.
Une fois l'enregistrement trouvé, je n'ai aucune raison (dans mon cas) de continuer à itérer sur les enregistrements suivants.
Du coup si je comprends bien on n'utilise plus la mémoire vive mais on perds en temps d'exécution le temps d'itérer sur le reste des enregistrements?
Cordialement,
Thomas
#10 C et C++ » utilisation de PQsetSingleRowMode » 27/08/2013 16:46:37
- thomasfr
- Réponses : 16
Bonjour,
J'aurais besoin d'un éclaircissement sur la fonction PQsetSingleRowMode.
Je l'utilise afin de lire des enregistrements dans une base après un appel à PQsendQueryPrepared.
Une fois l'enregistrement trouvé, j'aimerais débuter une nouvelle requête. La documentation indique que l'on doit appeler PQgetResult successivement jusqu'à ce que cette fonction retourne NULL avant de pouvoir envoyer une autre requête au serveur via PQsendQueryPrepared.
Ma question est : Comment éviter les appels successif à PGgetResult jusqu'à ce qu'il retourne NULL, peut-t-on annuler cette requête afin de ne pas avoir une boucle extrêmement longue du style :
res = PQgetResult(conn);
while (res!=NULL)
{
PQclear(res);
res = PQgetResult(conn);
}
PQclear(res);
J'ai essayé PQcancel, PQconsumeInput et PQflush sans succès.
Y-a-t-il un moyen d'annuler ce mode RowByRow au cours de la requête?
Cordialement,
Thomas
Pages : 1