直接查询 Table 和查询 Returns 相同 Table 的函数之间的区别
Difference Between Querying Table Directly and Querying Function that Returns that Same Table
我想要一个 returns 和 TABLE 的函数。我知道用户可以像 table 一样在选择和加入中使用函数调用。但是,select/join 能否使用函数 TABLE 返回的源 table 的索引?
例如:
"select id from permitted_resources() where id = 1"
会和 "select id from resources where id = 5"
一样吗? (假设资源 table 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;
Will "select id from permitted_resources() where id = 1" be the same as "select id from resources where id = 5"?
不,不会。 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
计划中甚至没有提到该功能。毫不奇怪,一个普通的 select 产生相同的计划:
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
我不知道这是否适用于更复杂的查询,但是这样一个函数与另一个函数之间的简单连接 table 显示了相同的行为。
我想要一个 returns 和 TABLE 的函数。我知道用户可以像 table 一样在选择和加入中使用函数调用。但是,select/join 能否使用函数 TABLE 返回的源 table 的索引?
例如:
"select id from permitted_resources() where id = 1"
会和 "select id from resources where id = 5"
一样吗? (假设资源 table 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;
Will "select id from permitted_resources() where id = 1" be the same as "select id from resources where id = 5"?
不,不会。 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
计划中甚至没有提到该功能。毫不奇怪,一个普通的 select 产生相同的计划:
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
我不知道这是否适用于更复杂的查询,但是这样一个函数与另一个函数之间的简单连接 table 显示了相同的行为。