Lors de l'exécution du code ci-dessous:PgSQL: Affectation d'une valeur de colonne à une variable rend paramètre de requête non lié
drop table if exists demo;
drop table if exists demo_test;
drop table if exists demo_result;
create table demo as select md5(v::text) from generate_series(1, 1000000) v;
create index on demo (md5 text_pattern_ops);
analyze demo;
create table demo_test
as select left(md5(v::text), 5) || '%' as "patt" from generate_series(2000000, 2000010) v;
create table demo_result (row text);
load 'auto_explain';
set auto_explain.log_min_duration to 0;
set auto_explain.log_analyze to true;
set auto_explain.log_nested_statements to true;
do $$
declare
row record;
pattern text;
begin
for row in select patt from demo_test loop
pattern = row.patt; -- <--- CRUCIAL LINE
insert into demo_result select * from demo where md5 like pattern;
end loop;
end$$;
PostgreSQL génère le plan de requête suivante:
2017-10-02 17:03:48 CEST [18038-23] app=psql [email protected] LOG: duration: 0.021 ms plan:
Query Text: insert into demo_result select * from demo where md5 like pattern
Insert on demo_result (cost=0.42..8.45 rows=100 width=33) (actual time=0.021..0.021 rows=0 loops=1)
-> Index Only Scan using demo_md5_idx on demo (cost=0.42..8.45 rows=100 width=33) (actual time=0.018..0.018 rows=1 loops=1)
Index Cond: ((md5 ~>=~ '791cc'::text) AND (md5 ~<~ '791cd'::text))
Filter: (md5 ~~ '791cc%'::text)
Heap Fetches: 1
Mais après avoir retiré pattern
variable, inline row.patt
en where
état:
insert into demo_result select * from demo where md5 like row.patt;
PostgreSQL traite le paramètre comme bind:
2017-10-02 17:03:02 CEST [17901-23] app=psql [email protected] LOG: duration: 89.636 ms plan:
Query Text: insert into demo_result select * from demo where md5 like row.patt
Insert on demo_result (cost=0.00..20834.00 rows=5000 width=33) (actual time=89.636..89.636 rows=0 loops=1)
-> Seq Scan on demo (cost=0.00..20834.00 rows=5000 width=33) (actual time=47.255..89.628 rows=1 loops=1)
Filter: (md5 ~~ $4)
Rows Removed by Filter: 999999
Je comprends que le dernier plan emploie balayage séquentiel, parce que PostgreSQL suppose que paramètres de liaison commencent par les caractères génériques.
Ma question est pourquoi les commutateurs d'affectation supplémentaires lient le paramètre on et off?
Question: Obtenez-vous les lignes attendues dans la table avec les deux méthodes? Assurez-vous simplement que nous n'obtenons pas de résultats inattendus en raison d'un conflit avec un mot réservé ou quelque chose d'étrange comme ça. –
Oui, je reçois les mêmes lignes avec les deux versions. –
Avez-vous essayé de convertir les deux en texte pour voir si cela change quelque chose? À ce stade, je ferais des essais et des erreurs pour tenter de discerner la cause des différents plans d'exécution. –