Comment définir la valeur du champ variable composite en utilisant le SQL dynamique

étant donné ce type:

-- Just for testing purposes:
CREATE TYPE testType as (name text)

je peux obtenir la valeur d'un champ dynamiquement avec cette fonction:

CREATE OR REPLACE FUNCTION get_field(object anyelement, field text) RETURNS text as
$BODY$
DECLARE
    value text;
BEGIN
    EXECUTE 'SELECT ."' || field || '"'
      USING object
       INTO value;

    return value;
END;
$BODY$
LANGUAGE plpgsql

Appel get_field('(david)'::testType, 'name') fonctionne comme prévu, le retour "david".

mais comment définir une valeur d'un champ dans un type composite? J'ai essayé ces fonctions:

CREATE OR REPLACE FUNCTION set_field_try1(object anyelement, field text, value text)
RETURNS anyelement
as
$BODY$
DECLARE
    value text;
BEGIN
    EXECUTE '."' || field || '" := '
      USING object, value;

    return object;
END;
$BODY$
LANGUAGE plpgsql

CREATE OR REPLACE FUNCTION set_field_try2(object anyelement, field text, value text)
RETURNS anyelement
as
$BODY$
DECLARE
    value text;
BEGIN
    EXECUTE 'SELECT  INTO ."' || field || '"'
      USING value, object;

    return object;
END;
$BODY$
LANGUAGE plpgsql

CREATE OR REPLACE FUNCTION set_field_try3(object anyelement, field text, value text)
RETURNS anyelement
as
$BODY$
DECLARE
    value text;
BEGIN
    EXECUTE 'BEGIN ."' || field || '" := ; SELECT ; END;'
       INTO object
      USING value, object;

    return object;
END;
$BODY$
LANGUAGE plpgsql

et quelques variantes. Appeler set_field_tryX ne marche pas. Je reçois toujours le message "ERREUR: erreur de syntaxe sur ou près...". Comment puis-je accomplir?

Notes:

  • le paramètre est anyelement et le champ peut être n'importe quel champ du type composite. Je ne peux pas juste utiliser un objet.nom.
  • Je m'inquiète de L'injection SQL. Tout conseil à ce sujet serait apprécié, mais ce n'est pas ma question.
9
demandé sur Erwin Brandstetter 2011-10-10 14:25:40

6 réponses

plus rapide avec hstore

depuis Postgres 9.0 , avec le module additionnel hstore installé dans votre base de données il ya une solution très simple et rapide avec le #= opérateur ça ...

remplacer [s] les champs de record par les valeurs correspondantes de hstore .

pour installer le module:

CREATE EXTENSION hstore;

exemples:

SELECT my_record #= '"field"=>"value"'::hstore;  -- with string literal
SELECT my_record #= hstore(field, value);        -- with values
Les valeurs

doivent être moulées à text et vice versa, évidemment.

exemple de fonctions plpgsql avec plus de détails:

presque aussi rapide avec json

il existe des solutions similaires, mais actuellement non documentées (à partir de la page 9.5) avec json (pg+ 9.3) ou jsonb (pg+ 9.4), intégré dans les Postgres, donc vous n'avez pas besoin d'un module supplémentaire.

voir la réponse de @Geir pour plus de détails.

sans hstore et json

si vous êtes sur une ancienne version ou si vous ne pouvez pas installer le module supplémentaire hstore ou ne pouvez pas supposer qu'il est installé, voici une version améliorée de ce que j'ai posté précédemment. Encore plus lent que l'opérateur hstore , cependant:

CREATE OR REPLACE FUNCTION f_setfield(INOUT _comp_val anyelement
                                          , _field text, _val text)
  RETURNS anyelement AS
$func$
BEGIN

EXECUTE 'SELECT ' || array_to_string(ARRAY(
      SELECT CASE WHEN attname = _field
                THEN ''
                ELSE '().' || quote_ident(attname)
             END AS fld
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = pg_typeof(_comp_val)::text::regclass
      AND    attnum > 0
      AND    attisdropped = FALSE
      ORDER  BY attnum
      ), ',')
USING  _comp_val, _val
INTO   _comp_val;

END
$func$ LANGUAGE plpgsql STABLE;

appel:

CREATE TEMP TABLE t( a int, b text);  -- Composite type for testing
SELECT f_setfield(NULL::t, 'a', '1');

Notes

  • une distribution explicite de la valeur _val au type de données cible n'est pas nécessaire, une chaîne littérale dans la requête dynamique serait forcée automatiquement, empêchant le sous-jeu sur pg_type . Mais j'ai fait un pas de plus:

  • remplacer quote_literal(_val) par insertion directe de valeur via la clause USING . Sauve un appel de fonction et deux plâtres, et est plus sûr de toute façon. text est forcé au type cible automatiquement dans PostgreSQL moderne. (N'a pas testé les versions avant 9.1.)

  • array_to_string(ARRAY()) est plus rapide que string_agg() .

  • pas de variables nécessaires, Pas de DECLARE . De moins en moins de devoirs.

  • Pas de sous-requête dans le SQL dynamique. ().field est plus rapide.

  • pg_typeof(_comp_val)::text::regclass

    fait la même chose que

    (SELECT typrelid FROM pg_catalog.pg_type WHERE oid = pg_typeof()::oid)

    pour les types composites valides, juste plus rapide.

    Cette dernière modification est basée sur l'hypothèse que pg_type.typname est toujours identique au pg_class.relname associé pour les types composites enregistrés, et la double coulée peut remplacer le sous-vernis. J'ai lancé ce test dans une grande base de données pour vérifier, et il est venu vide comme prévu:

    SELECT *
    FROM   pg_catalog.pg_type t
    JOIN   pg_namespace  n ON n.oid = t.typnamespace
    WHERE  t.typrelid > 0  -- exclude non-composite types
    AND    t.typrelid IS DISTINCT FROM
          (quote_ident(n.nspname ) || '.' || quote_ident(typname))::regclass
    
  • l'utilisation d'un paramètre INOUT un RETURN explicite . C'est juste un raccourci de notation. Pavel ne va pas aimer, il préfère une déclaration explicite RETURN ...

tout mis ensemble c'est presque deux fois plus rapide que la version précédente.


réponse originale (périmée):

le résultat est une version qui est ~ 2,25 fois plus rapide . Mais Je n'aurais probablement pas pu le faire sans la deuxième version de Pavel.

en outre, cette version évite la plupart du casting au texte et en arrière en faisant tout dans une seule requête, de sorte qu'il devrait être beaucoup moins sujet à l'erreur.

Testé avec PostgreSQL 9.0 et 9.1 .

CREATE FUNCTION f_setfield(_comp_val anyelement, _field text, _val text)
  RETURNS anyelement AS
$func$
DECLARE
   _list text;
BEGIN
_list := (
   SELECT string_agg(x.fld, ',')
   FROM  (
      SELECT CASE WHEN a.attname = 
              THEN quote_literal() || '::'|| (SELECT quote_ident(typname)
                                                FROM   pg_catalog.pg_type
                                                WHERE  oid = a.atttypid)
              ELSE quote_ident(a.attname)
             END AS fld
      FROM   pg_catalog.pg_attribute a 
      WHERE  a.attrelid = (SELECT typrelid
                           FROM   pg_catalog.pg_type
                           WHERE  oid = pg_typeof()::oid)
      AND    a.attnum > 0
      AND    a.attisdropped = false
      ORDER  BY a.attnum
      ) x
   );

EXECUTE 'SELECT ' || _list || ' FROM  (SELECT .*) x'
USING  
INTO   ;

RETURN ;
END
$func$ LANGUAGE plpgsql STABLE;
12
répondu Erwin Brandstetter 2017-07-22 01:24:17

j'ai écrit une deuxième version de la fonction setfield. Il fonctionne sur postgres 9.1 Je ne l'ai pas testé sur des versions plus anciennes. Ce n'est pas un miracle (vue performance), mais il est plus robuste et environ 8 fois plus rapide que le précédent.

CREATE OR REPLACE FUNCTION public.setfield2(anyelement, text, text)
 RETURNS anyelement
 LANGUAGE plpgsql
AS $function$
DECLARE 
  _name text;
  _values text[];
  _value text;
  _attnum int;
BEGIN
  FOR _name, _attnum
     IN SELECT a.attname, a.attnum
          FROM pg_catalog.pg_attribute a 
         WHERE a.attrelid = (SELECT typrelid
                               FROM pg_type
                              WHERE oid = pg_typeof()::oid)
           AND a.attnum > 0 
  LOOP
    IF _name =  THEN
      _value := ;
    ELSE
      EXECUTE 'SELECT (().' || quote_ident(_name) || ')::text' INTO _value USING ;
    END IF;
    _values[_attnum] :=  COALESCE('"' || replace(replace(_value, '"', '""'), '''', '''''') || '"', ''); 
  END LOOP;
  EXECUTE 'SELECT (' || quote_ident(pg_typeof()::text) || ' ''(' || array_to_string(_values,',') || ')'').*' INTO ; 
  RETURN ;
END;
$function$;
6
répondu Pavel Stehule 2015-11-02 11:02:55

mise à jour/mise en garde: Erwin souligne qu'il s'agit de actuellement non documenté , et le manuel indique qu'il ne devrait pas être possible de modifier les enregistrements de cette façon.

utiliser hstore ou Pavel's solution à la place.

cette solution simple basée sur json est presque aussi rapide que hstore, et ne nécessite que Postgres 9.3 ou plus récent. Ce devrait être une bonne option si vous ne pouvez pas utiliser l'extension hstore, et la différence de performance devrait être négligeable. Benchmarks: https://stackoverflow.com/a/28673542/1914376

a) nous pouvons soit le faire en ligne par cast/concat. La fonction Json nécessite Postgres 9.3:

SELECT json_populate_record( 
     record
    , ('{"'||'key'||'":"'||'new-value'||'"}')::json
);

b) ou en ligne en utilisant les fonctions de Postgres 9.4 .

SELECT json_populate_record (
      record
     ,json_object(ARRAY['key', 'new-value'])
);

Note: I choisi json_object(TABLEAU[clé,valeur]), car il est un peu plus rapide que json_build_object(clé,valeur):

pour cacher les détails de la fonte, vous pouvez utiliser a) dans une fonction, avec peu de surimpression.

CREATE FUNCTION x.setfield_json(in_element anyelement, key text, value text)
    RETURNS anyelement AS
$BODY$
    SELECT json_populate_record( in_element, ('{"'||key||'":"'||value||'"}')::json);
$BODY$ LANGUAGE sql;
3
répondu Geir Bostad 2017-05-23 11:47:36

"SELECT INTO" outside plpgsql (in dynamic SQL context) a un sens différent de celui que vous attendez - il stocke un résultat de requête à la table.

la Modification de n'importe quel champ est possible, mais pas simple

CREATE OR REPLACE FUNCTION public.setfield(a anyelement, text, text)
RETURNS anyelement
LANGUAGE plpgsql
AS $function$
begin
  create temp table aux as select .*;
  execute 'update aux set ' || quote_ident() || ' = ' || quote_literal();
  select into  * from aux;
  drop table aux;
  return ;
end;
$function$

Mais ce code n'est pas très efficace, n'est pas possible d'écrire ce bien en plpgsql. Tu peux trouver une bibliothèque C, ça devrait faire l'affaire.

2
répondu Pavel Stehule 2011-10-10 13:28:36

installation d'Essai et les critères de référence v2

Erwin encouragé à reproduire son benchmark dans ce fil ( https://stackoverflow.com/a/7782839/1914376 ), donc j'ai modifié son code avec des données de test synthétiques et j'ai ajouté à la fois la solution hstore et la solution json de ma réponse (et une solution json par Pavel trouvé dans un autre thread) Le benchmark est maintenant exécuté comme une requête, ce qui rend plus facile de capturer les résultats.

DROP SCHEMA IF EXISTS x CASCADE;
CREATE SCHEMA x;


-- Pavel 1:
--------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION x.setfield(anyelement, text, text)
RETURNS anyelement
LANGUAGE plpgsql
AS $function$
begin
  create temp table aux as select .*;
  execute 'update aux set ' || quote_ident() || ' = ' || quote_literal();
  select into  * from aux;
  drop table aux;
  return ;
end;
$function$;


-- Pavel 2 (with patches)
--------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION x.setfield2(anyelement, text, text)
 RETURNS anyelement
 LANGUAGE plpgsql
AS $function$
DECLARE
  _name text;
  _values text[];
  _value text;
  _attnum int;
BEGIN
  FOR _name, _attnum
     IN SELECT a.attname, a.attnum
           FROM pg_catalog.pg_attribute a
          WHERE a.attrelid = (SELECT typrelid
                                 FROM pg_type
                                WHERE oid = pg_typeof()::oid)
  LOOP
    IF _name =  THEN
      _value := ;
    ELSE
      EXECUTE 'SELECT (().' || quote_ident(_name) || ')::text' INTO _value USING ;
    END IF;
    _values[_attnum] :=  COALESCE('"' || replace(replace(_value, '"', '""'), '''', '''''') || '"', '');
  END LOOP;
  EXECUTE 'SELECT (' || pg_typeof()::text || '''(' || array_to_string(_values,',') || ')'').*' INTO ;
  RETURN ;
END;
$function$;


-- Erwin 1
--------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION x.setfield3(anyelement, text, text)
RETURNS anyelement
AS $body$
DECLARE
 _list text;

BEGIN
_list := (
   SELECT string_agg(x.fld, ',')
   FROM   (
      SELECT CASE WHEN a.attname = 
              THEN quote_literal()
              ELSE quote_ident(a.attname)
             END AS fld
      FROM   pg_catalog.pg_attribute a
      WHERE  a.attrelid = (SELECT typrelid
                           FROM   pg_type
                           WHERE  oid = pg_typeof()::oid)
      ORDER BY a.attnum
   ) x
);

EXECUTE '
SELECT ' || _list || '
FROM   (SELECT .*) x'
USING  
INTO   ;

RETURN ;
END;
$body$ LANGUAGE plpgsql;


-- Erwin 2
--------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION x.setfield4(INOUT _comp_val anyelement
                                       , _field text, _val text)
  RETURNS anyelement AS
$func$
BEGIN

EXECUTE 'SELECT ' || array_to_string(ARRAY(
      SELECT CASE WHEN attname = _field
                THEN ''
                ELSE '().' || quote_ident(attname)
             END AS fld
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = pg_typeof(_comp_val)::text::regclass
      AND    attnum > 0
      AND    attisdropped = FALSE
      ORDER  BY attnum
      ), ',')
USING  _comp_val, _val
INTO   _comp_val;

END
$func$ LANGUAGE plpgsql;


-- Pavel 3: json. (Postgres 9.4)
-- Found here: https://stackoverflow.com/a/28284491/1914376
--------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION x.setfield5(r anyelement, fn text, val text,OUT result anyelement)
 RETURNS anyelement
 LANGUAGE plpgsql
AS $function$
declare jo json;
begin
  jo := (select json_object(array_agg(key), 
                            array_agg(case key when fn then val
                                               else value end)) 
            from json_each_text(row_to_json(r)));
  result := json_populate_record(r, jo);
end;
$function$;


-- Json. Use built-in json functions (Postgres 9.3)
-- This is available from 9.3 since we create json by casting 
-- instead of using json_object/json_build_object only available from 9.4
--------------------------------------------------------------------------------------------------
CREATE FUNCTION x.setfield_json(in_element anyelement, key text, value text)
    RETURNS anyelement AS
$BODY$
    SELECT json_populate_record( in_element, ('{"'||key||'":"'||value||'"}')::json);
$BODY$ LANGUAGE sql;



--------------------------------------------------------------------------------------------------
-- Test setup
--------------------------------------------------------------------------------------------------

-- composite type for tests.
CREATE TYPE x.t_f as (
 id       int
,company  text
,sort     text
,log_up   timestamp
,log_upby smallint
);

-- Create temp table with synthetic test data
DROP TABLE IF EXISTS tmp_f;
CREATE TEMP table tmp_f AS
   SELECT ROW(i, 'company'||i, NULL, NULL, NULL)::x.t_f AS f
   FROM generate_series(1, 5000) S(i);



-- Run the benchmark
DO $$  DECLARE  start_time timestamptz; test_count integer; test_description TEXT; BEGIN

    test_count := 200;
    test_description := 'setfield, Pavel 1: temptable';
    start_time := clock_timestamp();    
    PERFORM x.setfield (f, 'company','new-value-'||md5(random()::text)) FROM tmp_f LIMIT test_count;
    RAISE NOTICE 'Test took: % ms (for % rows) Name: %', extract(MILLISECONDS FROM (clock_timestamp() - start_time))::INTEGER, test_count, test_description;

    test_count := 5000;
    test_description := 'setfield2, Pavel 2: reflection';
    start_time := clock_timestamp();
    PERFORM x.setfield2 (f, 'company','new-value-'||md5(random()::text)) FROM tmp_f LIMIT test_count;
    RAISE NOTICE 'Test took: % ms (for % rows) Name: %', extract(MILLISECONDS FROM (clock_timestamp() - start_time))::INTEGER, test_count, test_description;

    test_count := 5000;
    test_description := 'setfield3, Erwin 1: reflection';
    start_time := clock_timestamp();
    PERFORM x.setfield3 (f, 'company','new-value-'||md5(random()::text)) FROM tmp_f LIMIT test_count;
    RAISE NOTICE 'Test took: % ms (for % rows) Name: %', extract(MILLISECONDS FROM (clock_timestamp() - start_time))::INTEGER, test_count, test_description;

    test_count := 5000;
    test_description := 'setfield4, Erwin 2: reflection';
    start_time := clock_timestamp();
    PERFORM x.setfield4 (f, 'company','new-value-'||md5(random()::text)) FROM tmp_f LIMIT test_count;
    RAISE NOTICE 'Test took: % ms (for % rows) Name: %', extract(MILLISECONDS FROM (clock_timestamp() - start_time))::INTEGER, test_count, test_description;

    test_count := 5000;
    test_description := 'setfield5, Pavel 3: json (PG 9.4)';
    start_time := clock_timestamp();
    PERFORM x.setfield5 (f, 'company','new-value-'||md5(random()::text)) FROM tmp_f LIMIT test_count;
    RAISE NOTICE 'Test took: % ms (for % rows) Name: %', extract(MILLISECONDS FROM (clock_timestamp() - start_time))::INTEGER, test_count, test_description;

    test_count := 5000;
    test_description := 'setfield_json, Geir 1: casting (PG 9.3)';
    start_time := clock_timestamp();
    PERFORM x.setfield_json (f, 'company','new-value-'||md5(random()::text)) FROM tmp_f LIMIT test_count;
    RAISE NOTICE 'Test took: % ms (for % rows) Name: %', extract(MILLISECONDS FROM (clock_timestamp() - start_time))::INTEGER, test_count, test_description;

    --json_object(ARRAY(key,value]) is actually faster than json_build_object(key, value)
    test_count := 5000;
    test_description := 'no function/inlined: json_object (PG 9.4)';
    start_time := clock_timestamp();
    PERFORM json_populate_record( f, json_object(ARRAY['company', 'new-value'||md5(random()::text)]  )) FROM tmp_f LIMIT test_count;
    RAISE NOTICE 'Test took: % ms (for % rows) Name: %', extract(MILLISECONDS FROM (clock_timestamp() - start_time))::INTEGER, test_count, test_description;

    test_count := 5000;
    test_description := 'no function/inlined: hstore (PG 9.0)';
    start_time := clock_timestamp();
    PERFORM f #= hstore('company', 'new-value'||md5(random()::text))  FROM tmp_f LIMIT test_count;
    RAISE NOTICE 'Test took: % ms (for % rows) Name: %', extract(MILLISECONDS FROM (clock_timestamp() - start_time))::INTEGER, test_count, test_description;

END; $$;

Résultats des tests sur 9.4.1, win32, i5-4300U

NOTICE:  Test took: 1138 ms (for 200 rows) Name: setfield, Pavel 1: temptable
NOTICE:  Test took: 652 ms (for 5000 rows) Name: setfield2, Pavel 2: reflection
NOTICE:  Test took: 364 ms (for 5000 rows) Name: setfield3, Erwin 1: reflection
NOTICE:  Test took: 275 ms (for 5000 rows) Name: setfield4, Erwin 2: reflection
NOTICE:  Test took: 192 ms (for 5000 rows) Name: setfield5, Pavel 3: json (PG 9.4)
NOTICE:  Test took: 23 ms (for 5000 rows) Name: setfield_json, Geir 1: casting (PG 9.3)
NOTICE:  Test took: 25 ms (for 5000 rows) Name: no function/inlined: json_object (PG 9.4)
NOTICE:  Test took: 14 ms (for 5000 rows) Name: no function/inlined: hstore (PG 9.0)
1
répondu Geir Bostad 2017-05-23 12:26:43

Mise À Jour Mars 2015:

Largement dépassé maintenant. Considérons le nouveau benchmark de @Geir avec des variantes plus rapides.


installation d'Essai et les critères de référence

j'ai pris les trois solutions présentées (par Oct. 16th, 2011) et a effectué un test sur PostgreSQL 9.0. Vous trouverez la configuration complète ci-dessous. Seules les données de test ne sont pas incluses car j'ai utilisé une base de données de la vie réelle (données non synthétiques). Tout est encapsulé dans son propre schéma pour une utilisation non-intrusive.

je voudrais encourager quiconque veut reproduire le test. Peut-être avec postgres 9.1? Et ajouter vos résultats ici? :)

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;

-- Pavel 1
CREATE OR REPLACE FUNCTION x.setfield(anyelement, text, text)
RETURNS anyelement
LANGUAGE plpgsql
AS $function$
begin
  create temp table aux as select .*;
  execute 'update aux set ' || quote_ident() || ' = ' || quote_literal();
  select into  * from aux;
  drop table aux;
  return ;
end;
$function$;

-- Pavel 2 (with patches)
CREATE OR REPLACE FUNCTION x.setfield2(anyelement, text, text)
 RETURNS anyelement
 LANGUAGE plpgsql
AS $function$
DECLARE 
  _name text;
  _values text[];
  _value text;
  _attnum int;
BEGIN
  FOR _name, _attnum
     IN SELECT a.attname, a.attnum
           FROM pg_catalog.pg_attribute a 
          WHERE a.attrelid = (SELECT typrelid
                                 FROM pg_type
                                WHERE oid = pg_typeof()::oid) 
  LOOP
    IF _name =  THEN
      _value := ;
    ELSE
      EXECUTE 'SELECT (().' || quote_ident(_name) || ')::text' INTO _value USING ;
    END IF;
    _values[_attnum] :=  COALESCE('"' || replace(replace(_value, '"', '""'), '''', '''''') || '"', '');
  END LOOP;
  EXECUTE 'SELECT (' || pg_typeof()::text || '''(' || array_to_string(_values,',') || ')'').*' INTO ; 
  RETURN ;
END;
$function$;

-- Erwin 1
CREATE OR REPLACE FUNCTION x.setfield3(anyelement, text, text)
RETURNS anyelement
AS $body$
DECLARE
 _list text;

BEGIN
_list := (
   SELECT string_agg(x.fld, ',')
   FROM   (
      SELECT CASE WHEN a.attname = 
              THEN quote_literal()
              ELSE quote_ident(a.attname)
             END AS fld
      FROM   pg_catalog.pg_attribute a 
      WHERE  a.attrelid = (SELECT typrelid
                           FROM   pg_type
                           WHERE  oid = pg_typeof()::oid) 
      ORDER BY a.attnum
   ) x
);

EXECUTE '
SELECT ' || _list || '
FROM   (SELECT .*) x'
USING  
INTO   ;

RETURN ;
END;
$body$ LANGUAGE plpgsql;

-- composite type for tests.
CREATE TYPE x.t_f as (
 id       int
,company  text
,sort     text
,log_up   timestamp 
,log_upby smallint
);

-- temp table with real life test data
DROP   TABLE IF EXISTS tmp_f;
CREATE TEMP table tmp_f AS 
   SELECT ROW(firma_id,firma,sort,log_up,log_upby)::x.t_f AS f
   FROM   ef.firma
   WHERE  firma !~~ '"%';

-- SELECT count(*) FROM tmp_f;  -- 5183

-- Quick test: results are identical?
SELECT *,
       x.setfield (f, 'company','test')
      ,x.setfield2(f, 'company','test')
      ,x.setfield3(f, 'company','test')
 FROM tmp_f
LIMIT 10;

Repères

j'ai lancé les requêtes quelques fois pour remplir le cache. Les résultats présentés sont les meilleurs de cinq durées d'exécution totales avec EXPLAIN ANALYZE .

Rirst round avec 1000 lignes

le premier prototype de Pavel sort la mémoire partagée avec plus de lignes.

Pavel 1: 2445.112 ms

SELECT x.setfield (f, 'company','test') FROM tmp_f limit 1000;

Pavel 2: 263.753 ms

SELECT x.setfield2(f, 'company','test') FROM tmp_f limit 1000;

Erwin 1: 120.671 ms

SELECT x.setfield3(f, 'company','test') FROM tmp_f limit 1000;

un autre essai avec 5183 lignes.

Pavel 2: 1327.429 ms

SELECT x.setfield2(f, 'company','test') FROM tmp_f;

Erwin1: 588.691 ms

SELECT x.setfield3(f, 'company','test') FROM tmp_f;
1
répondu Erwin Brandstetter 2017-05-23 11:47:36