Vous n'êtes pas identifié(e).

#1 21/01/2011 12:06:15

Vitesse Postgres

Bonjour,

j'utilise pgadmin3 pour une base de données contenant beaucoup de lignes (137 000 lignes en moyenne).
Voici mon problème:
Quand je lance des requêtes ecrites en pl/pgsql elles sont beaucoup plus longues que l'équivalent en sql (3 fois plus longue environ, 115 000 ms contre 40 000 ms). Ces requêtes sont  à chaque fois des select avec condition (WHERE colonne=...), desfois j'ai des SELECT IN aussi.
En  pl/pgsq, les fonctions que j'écris renvoie un refcursor. Je fais ensuite un fetch all in nom_du_curseur.
Exemple: fun(r refcursor).
Utilisation:  select fun('r');
                Fetch All in r;

requête sql correspondante:  select id from nom_de_table1, nom_de_table2

Je croyais que postgres permettait d'être plus rapide que sql. Dois-je utiliser autre chose que le refcursor pour retourner un résultat? Le problème est-il du à autre chose que le code?

Merci d'avance

Hors ligne

#2 21/01/2011 14:47:12

Marc Cousin
Membre

Re : Vitesse Postgres

- Si vous voulez de l'aide sur un bout de code, postez le. C'est plus simple pour nous de voir ce qui ne va pas, que de le deviner smile
- Vous mélangez des concepts. «postgres permettait d'être plus rapide que sql» ne veut pas dire grand chose. sql est un langage de programmation, postgres un moteur de base de données, implémentant sql. Si ce que vous vouliez dire, c'est que plpgsql est plus rapide que sql, c'est faux, dans 99% des cas: l'optimiseur SQL est bien plus malin que la plupart des développeurs (moi compris smile ).
=> Si vous voulez comprendre pourquoi c'est lent, postez le code.

Un dernier point, 137000 lignes, c'est une très petite base de données, dans le monde postgres smile


Marc.

Hors ligne

#3 22/01/2011 18:58:30

Re : Vitesse Postgres

Bonjour,
merci de votre réponse. Donc en fait si j'ai bien compris plpgsql ne peut etre plus rapide que par rapport à plusieurs requêtes SQL exécutées à la suite. Mais considérant une seule requête on ne peut aller plus vite que sql.
Pour mes fonctions, le type de retour refcursor a été remplacé par setof (un type composite créé) et j'ai remarqué qu'alors que les temps d'éxécutions étaient similaires aux requêtes écrites en SQL. Si possible j'aimerais comprendre pourquoi. (Types d'algorithmes mis en jeu, ou gestion particulière de la mémoire ou autre mécanisme expliquant la différence de temps d'éxécution entre refcursor et setof).
2ème point:
je voulais faire une fonction booleenne is_included ayant comme paramètre un tableau d'id (clé de certaines tables) et qui renvoie true si l'entier passé en paramètre est inclus dans le tableau.
J'utilisais cette fonction comme condition (après le WHERE) dans des requête d'autres fonctions.
Exemple: select s_id where is_included(s_id, ARRAY [1,2,3]). Mais le temps d'exécution était très lent. J'ai finalement remplacé par select s_id in (1,2,3) et j'ai eu des temps bien meilleurs.
Dans la fonction utilisant le select in Je construis donc une chaine à partir du tableau en paramètre (de type text[] car les élément désignent des entiers, booléens ou autre. Je fais des CAST ensuite dans la requête).
Je voudrais là aussi savoir d'où vient la différence et si il existe un moyen de faire mieux encore.
En espérant ne pas étre trop confus.


Ci -dessous les  code de is_included puis de la fonction retournant un setof. Si vous trouvez des points où l'on peut faire mieux n'hésitez pas à le notifier.
Voici le code de is_included. On parcourt le tableau avec une boucle while, n'étant pa assez efficace je ne l'utilise plus:
CREATE OR REPLACE FUNCTION is_included(test integer, signatures integer[])
  RETURNS boolean AS
DECLARE
present boolean := false;
i integer;
BEGIN
i:=0;
while present=false AND i<= array_upper(signatures,1) loop
if test= signatures[i] then present:=true;
end if;
i:=i+1;
end loop;
return present;
end;
------------------------------------------------------------------------------------------------------------------------------------------------------

Ci-dessous un exemple de code retournant un setof:

--params contient une liste valeurs d'attributs qui sont propres à la table algo_table
--on n'a pas toujours les memes colonnes selon la table

create type request_sign_type as (signature int, vector bytea, id_image int , i_time double precision);

CREATE OR REPLACE FUNCTION request_id(algo_table text, params text[], user_paths text[] DEFAULT '{}'::text[])
  RETURNS setof request_sign_type AS
$BODY$
declare
selected_baz request_sign_type%rowtype;

s text;
s_paths text :='';

begin
-- on appelle une fonction qui fait que les element de user_paths  soient concaténés dans s_paths . Exemple: avec {path1, path2, path3} s_path contient 'AND path in (path1, path2, path)'
-- si user_path est vide s_path est vide (pas de conditions sur path). Je ne l'écris pas pour ne pas surcharger inutilement.
--path es une colonne de la table image

if(algo_table ='algo_gab') then
FOR selected_baz IN EXECUTE
' select s_id, s_vector, s_image, s_time from signature, image,algo_gab WHERE s_id=algo_gab.s_id AND signature.s_image=s_image
AND  norm_x ='||
  CAST (params[1] as int) ||'   --pas sur que c'est nécessaire
AND norm_y = '||CAST (params[2] as int) ||'
AND scale_numbers ='||CAST (params[3] as int) ||'
AND quadrant = '||CAST (params[4] as boolean)||' '  -- ici c'est un booléen
||s_paths
loop
RETURN NEXT selected_baz;
end loop;

if(algo_table ='algo_text') then ...
...
Return;

Dernière modification par kris_le_parisien (22/01/2011 20:18:17)

Hors ligne

#4 22/01/2011 19:10:38

Marc Cousin
Membre

Re : Vitesse Postgres

«Donc en fait si j'ai bien compris plpgsql ne peut etre plus rapide que par rapport à plusieurs requêtes SQL exécutées à la suite. Mais considérant une seule requête on ne peut aller plus vite que sql.»
Exactement

«Pour mes fonctions, le type de retour refcursor a été remplacé par setof (un type composite créé) et j'ai remarqué qu'alors que les temps d'éxécutions étaient similaires aux requêtes écrites en SQL. Si possible j'aimerais comprendre pourquoi.»
Il doit manquer un mot pour que je comprenne la question smile

Pour le reste :
is_included : je ne comprends pas l'intérêt, vous avez à votre disposition le mot clé ANY qui permet de savoir si un élément fait partie d'un tableau : sid = ANY (ARRAY[1,2,3])

Pour ce qui est des fonctions retournant des SETOF, de mémoire, tout le résultat est alloué dans la fonction avant d'être retourné à l'appelant. C'est donc plus lent que de retourner un refcursor par exemple, puisque le refcursor n'est, en quelque sorte, qu'un pointeur sur le résultat, ce pointeur pouvant d'ailleurs être retourné avant que le résultat soit calculé entièrement.


Marc.

Hors ligne

#5 22/01/2011 20:28:02

Re : Vitesse Postgres

merci je vais voir si le ANY est meilleur que la concaténation de chaines. Par contre les fonctions retournant un SETOF ont des temps d’exécution du même ordre que les requêtes  SQL équivalentes. Les fonctions retournant un refcursor sont elles 3 fois plus lentes (en ajoutant ensuite un "Fetch all in nom_du_curseur"). J'aimerais savoir ce qui cause cette différence.
exemple du refcursor :
select fun('r'); Fetch All in r;  --> ceci est 3 fois plus long.

Hors ligne

#6 22/01/2011 20:45:00

Marc Cousin
Membre

Re : Vitesse Postgres

Étrange pour le cas du fetch. Il doit y avoir une cause autre. Si possible, postez le code de la fonction, sans cela on reste trop dans le flou.


Marc.

Hors ligne

#7 23/01/2011 21:38:25

Re : Vitesse Postgres

Bonjour,
j'ai fait de multiples tests en comparant les temps d’exécution des fonctions renvoyant un refcursor, celles renvoyant un setof de type composite et ceux des requêtes SQL.
A chaque fois j'ai obtenu des temps d’exécution similaires sauf dans un cas.
Ce cas est quand je fais un select sur une ou plusieurs colonnes dont une contient des valeurs de type bytea.

Exemple:
select IMAGE.id,id_sign, vector from image,signature,algo_gab where IMAGE.id=id_image and signature.id_sign=algo_gab.id_sign; -- vector est de type bytea.

-- Dans ce cas là seulement la fonction renvoyant un refcursor est 3 fois plus longue (desfois plus encore)que les deux autres. La fonction retournant un setof a par contre toujours un temps equivalent à la requête SQL.
Pour tout autre combinaison de colonnes sélectionnées, si aucune n'est de type  bytea alors les 3 ont des temps similaires.
--Voici un exemple de valeur de vector:
" 1.11498E+02, 1.35706E+02, 2.88843E+02, 1.30191E+02, 1.89009E+02, 1.88747E+02, 1.16372E+03, 1.71711E+02, 1.84266E+02, 2.83373E+02, 2.02455E+03, 2.50216E+02, 2.94586E+02, 4.01803E+02, 2.74225E+03, 3.59621E+02, 2.37780E+02, 4.26430E+02, 4.90676E+03, 3.64694E+02"

--C'est utilisé pour stocker des résultats d'algorithmes, mais ce n'est pas moi qui gère le calcul.
-- on réfléchit à remplacer ce type de colonne

J'aimerais savoir si vous avez une idée de pourquoi le type bytea entraine une différence de temps quand on utilise refcursor ou setof.
Ci- dessous le code des 2 fonctions et de la requête.
Merci.

Exemple:
tables:  image (id, ... autres paramètres...)  signature(id_sign,id_image) algo_gab (id, vector, id_sign)
IMAGE.id ALGO_GAB.id et id_sign sont des entiers, id_image est une clé étrangère référençant IMAGE.id.
vector est de type bytea.


Requête SQL:
select IMAGE.id,id_sign, vector from image,signature,algo_gab where IMAGE.id=id_image and signature.id_sign=algo_gab.id_sign; --> 23 541 ms

Fonction refcursor:
CREATE OR REPLACE FUNCTION fun_ref(curs refcursor)  --> 116 169 ms
  RETURNS refcursor AS
begin
open curs for execute 'select IMAGE.id,id_sign, vector from image,signature,algo_gab where IMAGE.id=id_image and signature.id_sign=algo_gab.id_sign'
return curs;
end;

Fonction setof:

create type image_sign_gab as (i int, sign int, vector bytea);

CREATE OR REPLACE FUNCTION fun_setof () --> 18 951 ms
  RETURNS setof image_sign_gab AS
$BODY$
declare
s image_sign_gab %rowtype;
begin
for s in execute 'select IMAGE.id,id_sign, vector from image,signature,algo_gab where IMAGE.id=id_image and signature.id_sign=algo_gab.id_sign ' loop
return next s;
end loop;
return;
end;

Dernière modification par kris_le_parisien (23/01/2011 22:28:21)

Hors ligne

#8 24/01/2011 14:56:31

Marc Cousin
Membre

Re : Vitesse Postgres

Avant d'aller plus loin (je ne vois rien de bizarre dans le code), pouvez vous réessayer la procédure en refcursor avec le paramètre 'cursor_tuple_fraction' à 1 au lieu de 0.1 ?


Marc.

Hors ligne

#9 24/01/2011 21:27:32

Re : Vitesse Postgres

Bonjour,
Pour modifier cursor_tuple_fraction je suis allé dans une fenêtre de requête et j'ai exécuté SET cursor_tuple_fraction to 1.0. Puis 'ai lancé dans la même fenêtre de requête:
SELECT fun_ref('r');
fetch all in r;

La fonction fun_ref est la même que dans le message précédent. J'obtiens maintenant un temps de 22 575 ms (on avait avant 116 169 ms).
Cela donne un temps proche de la requête SQL, donc un résultat qui convient.
En lisant la doc, je n'ai pas trop compris l' influence du  temps total estimé ou la vitesse à laquelle les premiers enregistrements arrivent sur le temps d’exécution.

Etant encore novice en postgres j'aurais quelques questions à propos de ce résultat.
Ce nouveau résultat permet-t-il d'en apprendre plus sur la raison de la lenteur de fun_ref quand le paramètre est à 0.1?
Est-ce juste que l'on force la requête à se comporter comme si c'était une requête SQL classique au lieu de se comporter comme un curseur (qui serait le comportement normal car cette fonction renvoit un refcursor).
Enfin cette solution semble temporaire, puisque je ne peux changer le paramètre qu'au moment de l'execution. Mais les procédures que je code ont pour but d'être utilisés sur le serveur par d'autres programmes (dans d'autres langages: python, ADA...). Ce résultat donne-t-il des renseignements pour effectuer d'autres opérations par la suite?

Merci

Dernière modification par kris_le_parisien (24/01/2011 21:30:37)

Hors ligne

#10 24/01/2011 21:38:48

Marc Cousin
Membre

Re : Vitesse Postgres

Oui, ce nouveau résultat expliquer la cause du ralentissement. Par défaut, PostgreSQL, quand vous utilisez un curseur, part de l'hypothèse que vous n'allez récupérer que 10% des enregistrements générés (il n'a aucun moyen de savoir si vous allez tout utiliser). Il choisit donc un plan qui ramène le plus vite possible ces 10 premiers pourcents, au détriment des enregistrements suivants.

Ce paramètre peut être modifé:
- globalement (postgresql.conf)
- par utilisateur (alter user xxx SET cursor_tuple_fraction to 1.0)
- par base (alter database yyy SET…)
- par fonction (create function .... SET …)
- dans le code de la fonction (par un SET)

Cela devrait vous donner suffisamment de souplesse, je pense smile


Marc.

Hors ligne

#11 24/01/2011 23:21:39

Re : Vitesse Postgres

Bonjour,
merci de votre réponse. J'aimerais si possible obtenir quelques précisions sur certains points.
Vous avez dit: " part de l'hypothèse que vous n'allez récupérer que 10% des enregistrements générés  (il n'a aucun moyen de savoir si vous allez tout utiliser)."

Je n'ai pas bien saisi la différence entre générer et récupérer. Est-ce que générer= mettre  les résultats de la requête (un enregistrement=1 ligne) en mémoire, et utilisez= mettre ces résultats en sortie (en créant un ensemble curseur et en y insérant les lignes)? 

Si je modifie  le paramètre  globalement (postgresql.conf), cela peut -il avoir des conséquences sur d'autres fonctions? (J'ai testé sur d'autres fonctions refcursor où le select ne prend pas de colonnes de type bytea, et elle semblent un tout petit peu plus rapide--> 21 853 ms au lieu de 28 058 ms)

Enfin d'une manière générale, si par exemple je n'ai pas besoin que le résultat d'une fonction renvoyant un ensemble de ligne (par refcursor ou setof) puisse être récupérer par une autre fonction plpgsql (dans ce cas là on utilise refcursor je crois),
il y a -t-il d'autres intérêt à privilégiers le type de retour refcursor plutôt que setof?  Le premier type offrirait-t-il plus de facilités pour certaines opérations?

Encore merci pour vos réponses

Dernière modification par kris_le_parisien (25/01/2011 00:01:44)

Hors ligne

#12 25/01/2011 10:05:46

Marc Cousin
Membre

Re : Vitesse Postgres

Le moteur ne 'produit' pas tous les enregistrements avant de vous les retourner. Il prépare un plan d'exécution, et le déroule au fur et à mesure que vous lui demandez des enregistrements (enfin, sauf cas particulier, mais vous n'êtes pas dans ces cas là).

Donc quand vous lui demandez d'exécuter une requête, il doit se poser la question: «l'utilisateur va t'il vouloir tous les enregistrements que je vais pouvoir lui fournir par la requête demandée ?». Suivant la réponse à cette question, il ne choisira pas le même plan. Si l'utilisateur veut tous les enregistrements, il privilégiera un plan ramenant le plus rapidement possible l'ensemble des enregistrements (le plan ramenant le plus rapidement le dernier enregistrement, en fait). Si l'utilisateur ne veut pas tous les enregistrements, mais seulement une certaine fraction, il va choisir un plan ramenant cette fraction le plus rapidement possible.

Par défaut, sous PostgreSQL, on considère que si vous faites usage d'un curseur, c'est que vous ne voulez pas forcément parcourir tout le résultat. Vous voulez peut-être parcourir le résultat jusqu'à ce qu'une condition soit vérifiée… Ou alors vous avez un calcul complexe à effectuer sur chaque enregistrement, et il se peut que le temps global d'exécution de votre traitement soit plus rapide si vous récupérez les premiers enregistrements assez rapidement (et que donc vous pouvez commencer à travailler rapidement, pendant que le moteur vous prépare les enregistrements suivants…). Par défaut, il considère donc que si vous déclarez un curseur, vous allez vouloir récupérer 10% des enregistrements, et il calcule donc le plan le plus rapide pour vous retourner ces 10%. Plan qui sera moins bon pour récupérer 100% des enregistrements, bien sûr. C'est à ça que sert cursor_tuple_fraction.

Si vous modifiez le paramètre globalement, vous dites simplement à PostgreSQL que vous allez, pour toutes les requêtes utilisant un curseur, récupérer ce nouveau pourcentage des enregistrements. Si vous récupérez toujours tout le résultat, vous n'aurez que des gains.

Je ne comprends pas votre dernière question.


Marc.

Hors ligne

#13 25/01/2011 15:01:03

Re : Vitesse Postgres

Bonjour,

merci pour votre réponse, c'est très clair.

Ma dernière question est plus d'ordre générale. Nous hésitions entre choisir des fonctions renvoyant des refcursor ou renvoyant des setof. On voudrait savoir, en supposant que l'on n'ait pas besoin de transmettre les résultats d'une fonction à une autre (dans ce cas on utilise forcément refcursor),  quels mode de retour ,  refcursor ou setof, présente le plus d'avantages en général?

Lequel est privilégié en général par les développeurs, et si possible si vous auriez des exemples de cas où un des types est avantageux par rapport à l'autre.

merci encore

Dernière modification par kris_le_parisien (25/01/2011 15:01:40)

Hors ligne

#14 25/01/2011 15:07:19

Marc Cousin
Membre

Re : Vitesse Postgres

Habituellement, on utilise des setof.

C'est exactement la même différence que dans la programmation structurée habituelle: préférez vous une fonction qui vous renvoie un tableau de valeurs prédéfinies, ou un pointeur vers quelque chose d'indéfini (un curseur ici, c'est un peu comme renvoyer un void* en C). Si vous savez que la fonction va toujours vous ramener un type bien défini, autant le définir, et l'utiliser.

Une fonction définie en setof peut être utilisée dans un select * : select * from ma_fonction(). Une fonction retournant un refcursor demande à l'appelant de faire le travail sur le curseur.

Le refcursor a toutefois son utilité, entre autres si vous ne savez pas à coup sûr ce que va retourner votre fonction. Ou que vous voulez vraiment laisser le contrôle de l'exécution à l'appelant.


Marc.

Hors ligne

#15 25/01/2011 20:28:04

Re : Vitesse Postgres

Bonjour,

J'ai un problème avec postgresql.conf. Je l'ai ouvert avec pgadmin et je n'y ait pas trouvé cursor_tuple_fraction.
Je l'ai alors ouvert manuellement avec un editeur de texte (gedit) et j'y ai bien trouvé cursor_tuple_fraction. J'y ai donc mis la valeur de 1.0 au lieu de 0.1. Mais pgadmin n'en tient pas compte (je vérifie alors avec show all). J'ai quitter puis relancé pgadmin mais ça ne change rien. J'ai aussi essayé en enlevant le # devant cursor_tuple_fraction mais ça ne change rien
Savez-vous si je dois faire autre chose?

Hors ligne

#16 25/01/2011 20:31:46

Marc Cousin
Membre

Re : Vitesse Postgres

pgadmin n'est qu'une interface graphique. Il faut demander à Postgres de relire son fichier de configuration.


Marc.

Hors ligne

#17 25/01/2011 22:31:02

Re : Vitesse Postgres

Bonjour,
pour la modification du fichier j'ai finalement réussi.
J'ai aussi essayé d'utiliser ANY dans mes requêtes.
Lorsque les paramètres auquels je compare les tableaux sont des entiers, pas de problème ça marche. Mais quand les éléments auxquels je compare e tableau sont de type text alors il ne trouve aucun résultat, comme si il n'arrivait pas à lire correctement la chaine présente dans le tableau.

exemple:

j'ai une table image avec notamment 2 attributs id_image de type int et path de type text.

voici le corps de la fonction. C'est quasiment le même dans les 2 cas:

CREATE OR REPLACE FUNCTION test_any(curs refcursor, params text[])
  RETURNS refcursor AS
$BODY$begin

open curs for execute 'select * from image where   ATTRIBUT  =ANY('||quote_literal(params)||')';  --> Dans la suite ATTRIBUT  sera remplacé soit par id_image soit par path
return curs;
end;$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION test_any(refcursor, text[]) OWNER TO postgres;
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

si je fais les appels suivants avec ATTRIBUT  = id_image:

SELECT test_any('r',TAB);  où TAB est l'un des motifs suivants:  ARRAY ['1','2'], ou '{1,2}'
fetch all in r;

on obtient les résultats souhaités.

Si maintenant ATTRIBUT  = path

je fais les appels suivants:

SELECT test_any('r',TAB);  où TAB est l'un des motifs suivants:  ARRAY['partA, partB'], ou '{partA,partB}'
fetch all in r;

Là postgres n'arrive à trouver aucun resultat. Pourtant je sais que les chaines sont correctes, car ça a fonctionné avec ma méthode précédente où je concaténais tous les éléments d'un tableau dans une chaine.

Sauriez-vous si je dois modifier la syntaxe quelque part?

merci
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Ci-dessous je mes le code de création de chaines à partir d'un tableau au cas où ça puisse servir pour comprendre le problème:

CREATE OR REPLACE FUNCTION sqltext_from_table_text(param_table text[])
  RETURNS text AS
$BODY$declare
s text;

begin
s:='';
for i in 1..array_upper(param_table,1) loop
if i=array_upper(param_table,1) then
s:= s || param_table[i];
else s:= s||param_table[i]||',';
end if;
end loop;
return s;

end;$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION sqltext_from_table_text(text[]) OWNER TO postgres

Dernière modification par kris_le_parisien (25/01/2011 22:32:21)

Hors ligne

#18 26/01/2011 09:45:11

Marc Cousin
Membre

Re : Vitesse Postgres

quote_literal n'est pas fait pour traiter un tableau. Même si vous avez de la chance que ça marche pour le cas entier.
Plutôt que d'utiliser :

open curs for execute 'select * from image where   ATTRIBUT  =ANY('||quote_literal(params)||')';

Utilisez :

open curs for execute 'select * from image where   ATTRIBUT  =ANY($1)' USING params;

Je pense que ça devrait fonctionner tel quel, sans s'embêter à devoir quoter le tableau.


Marc.

Hors ligne

#19 26/01/2011 13:22:48

Re : Vitesse Postgres

Bonjour,

J'ai essayé d'écrire ANY comme vous avez dit, mais la fonction ne compile pas:
début de la fonction:
CREATE OR REPLACE FUNCTION test_any(curs refcursor, params text[])
  RETURNS refcursor AS
...
J'ai écrit:
open curs for execute 'select * from image where path=ANY('||$1||')' USING params ; 
-->
J'obtiens alors:
ERROR:  syntax error at or near "USING"
LINE 1: ... 'select * from image where path=ANY('|| $1 ||')' USING  $2
                                                             ^
QUERY:  SELECT  'select * from image where path=ANY('|| $1 ||')' USING  $2
CONTEXT:  SQL statement in PL/PgSQL function "test_any" near line 3


si je mes :
ANY('||$2||')' USING params, j'ai :

ERROR:  syntax error at or near "$1"
LINE 1: SELECT  'select * from image where path=ANY(' $1 ')' USING  ...
                                                      ^
QUERY:  SELECT  'select * from image where path=ANY(' $1 ')' USING  $1
CONTEXT:  SQL statement in PL/PgSQL function "test_any" near line 3



Si je ne mes pas les || autour de $1, il me dit qu'il y a une erreur de syntaxe.

Faut-t-il rajouter quelque chose?
----------------------------------------------------------------------------------------------------------------------------------------------------------

Je voulais aussi revenir sur les temps d'execution. Quand cursor_tuple_fraction était à 0.1 la fonction retournant un refcursor était bien plus longue qu'une requête SQL si le select récupérait des colonnes de type bytea, mais dans les autres cas les temps étaient équivalents.

Exemple: si la requête de la fonction était:

--> avec vector de type bytea. On a alors un temps d'execution de la fonction au moins 3 fois plus long que celui de la requête SQL.
open curs for execute 'select IMAGE.id,id_sign, vector from image,signature,algo_gab where IMAGE.id=id_image and signature.id_sign=algo_gab.id_sign'

--> sinon les temps sont quasi-similaires:
open curs for execute 'select IMAGE.id,id_sign, id_algo_gab from image,signature,algo_gab where IMAGE.id=id_image and signature.id_sign=algo_gab.id_sign' --> temps similaires à la requête en SQL

Cela signifie-t-il que le plan execution "fast-start" etait suffisant quand la taille des valeurs de colonnes n'étaient pas trop gros (int, text...): la méthode de récupérer le plus rapidement possible 10% des enregistrements étaient la meilleure.

Mais quand une des colonnes était de type bytea (par exemple vector qui semble contenir des valeurs assez grosses ), ramener très vite 10% des enregistrements n'était pas la bonne méthode. Il était mieux d'attendre de générer tous les enregistrements avant de les récupérer.

De plus puisque les temps des fonctions postgres et des requêtes étaient très différents quand cursor_tuple_fraction était à 0.1, cela signifie-t-il que les plans d'execution de postgres peuvent être très différents de ceux en SQL?

Cette interprétation vous semble -t- elle correcte?

merci

Dernière modification par kris_le_parisien (26/01/2011 13:33:40)

Hors ligne

#20 26/01/2011 13:30:18

Marc Cousin
Membre

Re : Vitesse Postgres

Il ne faut ni quotes ni || autour de $1. $1 est un paramètre de la requête.

Le fait que la fast-start soit suffisante quand les colonnes ne sont pas trop grosse est un coup de chance je pense.

Oui, le plan dépend de cursor_tuple_fraction, bien sûr. Justement, suivant la valeur, il va privilégier un plan ramenant rapidement des enregistrements ou non.


Marc.

Hors ligne

#21 26/01/2011 13:44:44

Re : Vitesse Postgres

J'ai essayé sans quotes ni || autour de $1.
voici la fonction:
CREATE OR REPLACE FUNCTION test_any(curs refcursor, params text[])
RETURNS refcursor AS
$BODY$begin
open curs for execute 'select * from image where path=ANY($1)' USING params ;
return curs;
end;

il me mes une erreur de syntaxe au niveau de USING:

ERROR:  syntax error at or near "USING"
LINE 1: SELECT  'select * from image where path=ANY($1)' USING  $1
                                                         ^
QUERY:  SELECT  'select * from image where path=ANY($1)' USING  $1
CONTEXT:  SQL statement in PL/PgSQL function "test_any" near line 3

Faut-il ajouter quelque chose?

Hors ligne

#22 26/01/2011 13:59:03

Marc Cousin
Membre

Re : Vitesse Postgres

Étrange, ici ça passe.

Quelle version de PG ?


Marc.

Hors ligne

#23 26/01/2011 15:16:35

Re : Vitesse Postgres

C'est la version 8.4.

Hors ligne

#24 26/01/2011 16:12:52

Marc Cousin
Membre

Re : Vitesse Postgres

Ok. C'est une nouveauté syntaxique de la 9.0.

Je ne vois pas comment le faire proprement en 8.4. En tout cas pas avec quote_litteral, ça ne marche pas sur les array.

Il va peut-être falloir que vous écriviez votre quote_array pour les chaines de caractères. En tout cas, ça risque de ne pas être très beau.

Quelqu'un d'autre a une idée ? (gleu par exemple smile )


Marc.

Hors ligne

#25 26/01/2011 21:39:42

gleu
Administrateur

Re : Vitesse Postgres

En dehors de coder son propre quote_array ? ce qui risque en effet d'être pas beau du tout ? non aucune idée.


Guillaume.

Hors ligne

Pied de page des forums