【问题标题】:PgSQL: Assigning a column value to a variable makes query parameter unboundPgSQL:将列值分配给变量使查询参数未绑定
【发布时间】:2018-03-13 17:02:28
【问题描述】:

运行以下代码时:

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 生成以下查询计划:

2017-10-02 17:03:48 CEST [18038-23] app=psql barczynski@barczynski 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

但在删除pattern 变量,并在where 条件中内联row.patt 之后:

insert into demo_result select * from demo where md5 like row.patt;

PostgreSQL 将参数视为绑定:

2017-10-02 17:03:02 CEST [17901-23] app=psql barczynski@barczynski 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

我知道后一种计划采用顺序扫描,因为 PostgreSQL 假定绑定参数以通配符开头。

我的问题是为什么额外的赋值会打开和关闭绑定参数?

【问题讨论】:

  • 问题:您是否使用这两种方法在表中获得了预期的行?只需确保我们不会因为与保留字或类似的奇怪内容冲突而得到意外结果。
  • 是的,我在两个版本中得到了相同的行。
  • 您是否尝试过将两者都转换为文本以查看是否有任何改变?在这一点上,我会反复试验,试图找出不同执行计划的原因。
  • Gary 下面解释了不同执行计划的原因。我的问题是为什么将行分配给变量会关闭绑定参数。

标签: postgresql plpgsql sqlbindparameter


【解决方案1】:

不同之处在于优化器在查看查询时可用的数据。

对于第一个查询,绑定参数可供优化器查看。所以它看到没有通配符就知道可以使用索引了。

insert into demo_result select * from demo where md5 like '791cc%';

第二个查询不知道模式会是什么样子,所以它不能假设索引是好的。

我怀疑如果您有一个带有前导通配符“%791cc”的模式,您会看到两种方法都使用相同的查询计划,因为 seq_scan 将用于两种方法。

【讨论】:

  • 我同意这就是它的样子,但row 也是一个变量。为什么PostgreSQL可以优化text,却不能record类型?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多