Vous n'êtes pas identifié(e).
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
- 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
- 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 ).
=> 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
Marc.
Hors ligne
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
«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
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
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
É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
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
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
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
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
Marc.
Hors ligne
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
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
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
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
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
pgadmin n'est qu'une interface graphique. Il faut demander à Postgres de relire son fichier de configuration.
Marc.
Hors ligne
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
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
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
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
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
Étrange, ici ça passe.
Quelle version de PG ?
Marc.
Hors ligne
C'est la version 8.4.
Hors ligne
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 )
Marc.
Hors ligne
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