【问题标题】:Difference Between Querying Table Directly and Querying Function that Returns that Same Table直接查询表和查询返回同一张表的函数的区别
【发布时间】:2020-08-27 13:04:34
【问题描述】:

我想要一个返回 TABLE 的函数。我知道用户可以像表格一样在选择和连接中使用函数调用。但是,select/join 是否能够使用函数 TABLE 返回的源表的索引?

例如: "select id from permitted_resources() where id = 1" 会和"select id from resources where id = 5" 一样吗? (假设资源表id列有索引。)

CREATE OR REPLACE FUNCTION permitted_resources()
  RETURNS TABLE (id   int, name varchar(10)) AS
$func$
BEGIN
   RETURN QUERY
   SELECT r.id, r.name from resources r; 
END
$func$  LANGUAGE plpgsql;

【问题讨论】:

    标签: postgresql set-returning-functions


    【解决方案1】:

    “从 allowed_resources() where id = 1 中选择 id”是否与“从其中 id = 5 的资源中选择 id”相同?

    不,它不会。 PL/pgSQL 函数是优化器的黑匣子。

    如果您想实现类似的目标,请使用language sql 函数:

    CREATE OR REPLACE FUNCTION permitted_resources()
      RETURNS TABLE (id   int, name varchar(10)) AS
    $func$
       SELECT r.id, r.name from resources r; 
    $func$  
    LANGUAGE sql
    stable;
    

    我们可以使用以下设置进行测试:

    create table test 
    (
      id integer primary key, 
      some_nr integer default random() * 1000 + 1,
      some_date date default current_date,
      some_text text default md5(random()::text)
    );
    
    insert into test (id) 
    select *
    from generate_series(1,1e6);
    

    现在创建一个 PL/pgSQL 函数:

    create function get_data1()
    returns setof test
    as
    $$
    begin
     return query
       select *
       from test;
    end;   
    $$
    language plpgsql
    stable;
    

    还有一个 SQL 函数:

    create function get_data2()
    returns setof test
    as
    $$
     select *
     from test;
    $$
    language sql
    stable;
    

    让我们看看执行计划的样子:

    explain (analyze)
    select *
    from get_data1() -- this is the PL/pgSQL function
    where id = 1234; 
    

    产生以下执行计划:

    Function Scan on get_data1  (cost=0.25..4.75 rows=5 width=44) (actual time=261.033..361.218 rows=1 loops=1)
      Filter: (id = 1234)
      Rows Removed by Filter: 999999
    Planning Time: 0.033 ms
    Execution Time: 371.302 ms
    

    显然它首先检索所有行,然后再次丢弃它们

    然而,

    explain (analyze)
    select *
    from get_data2() -- the "SQL" function
    where id = 1234; 
    

    产生以下执行计划:

    Index Scan using test_pkey on test  (cost=0.42..2.43 rows=1 width=45) (actual time=0.015..0.017 rows=1 loops=1)
      Index Cond: (id = 1234)
    Planning Time: 0.119 ms
    Execution Time: 0.031 ms
    

    计划中甚至不再提及该功能。毫不奇怪,简单的选择会产生相同的计划:

    explain (analyze)
    select *
    from test
    where id = 1234;
    
    Index Scan using test_pkey on test  (cost=0.42..2.43 rows=1 width=45) (actual time=0.014..0.014 rows=1 loops=1)
      Index Cond: (id = 1234)
    Planning Time: 0.058 ms
    Execution Time: 0.026 ms
    

    我不知道这是否适用于更复杂的查询,但是这样的函数和另一个表之间的简单连接会显示相同的行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-09
      • 2013-07-19
      • 1970-01-01
      • 1970-01-01
      • 2013-11-06
      • 2013-07-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多