我在plpgsql函数中有一个查询(见下文,为了清楚起见而简化),在4或5次运行后减速约5倍(运行时间从~700 ms到~3.5秒)。如果我删除并重新创建该功能,它将重新开始:快速约5次然后慢。所以,似乎查询优化器有一些问题,但我无法获得查询计划,因为它在函数中。如果我在具有相同输入的函数外部运行查询,则无论运行多少次都可以正常运行。如果我注释掉3个左连接,保持它在函数内部,再次运行正常。所以,我得出的结论是它与左连接有关,但那是关于它的。
有关查询的更多信息:在返回with as
约5000行和40行后,它有一个data
子句;然后,它会自行连接3次以将一些信息从行移动到列(这会将行减少到小于1000)。
create or replace function public.a_function(
-- 5 input parameters here
)
returns table (a text, b integer, ...) -- about 40 output columns
as $$
declare
...
begin
... --logic to prepare two arrays used in query below: array_a and array_b
return query
with data as ( -- this part of the query returns ~5000 rows and 40 columns
select d.*
from public.dashboard_data_view d -- ~10 million rows in this view
where d.organization_id = any (array_a) -- array_a: 4 values in int[]
and d.element_id = any (array_b) -- array_b: ~10,000 values in int[]
)
select c.*, c.value, d.value, r.value, s.value
from (select * from data where data.population = 'C') c -- this reduces rows down to ~1000
left join (select * from data where data.population = 'D') d on d.common_id = c.common_id
left join (select * from data where data.population = 'R') r on r.common_id = c.common_id
left join (select * from data where data.population = 'S') s on s.common_id = c.common_id
;
end
$$ language plpgsql stable;
;
平台信息:Ubuntu 14上的Postgres 9.3 LTS在4 GB ram和2 cpus的Vagrant VM上运行。 shared_buffers
= 1000 MB(总数的1/4)和work_mem
= 128 MB(开发机器,并行进行的并不多)。
那么,可能导致放缓的原因或我可以做些什么来进一步调查?
更新: 我将array_b的值作为文字粘贴到查询中(而不是使用变量),它运行正常。在视图中大约有16K的element_id,并且过滤约10K左右,似乎优化器决定在5次之后使用顺序扫描而不是索引扫描。这是我的怀疑,但我不确定。
答案 0 :(得分:0)
由于查询/优化器更喜欢array_b的文字,我切换到动态sql,并将变量作为文字输入:
return query
execute format(
'with data as ( -- this part of the query returns ~5000 rows and 40 columns
select d.*
from public.dashboard_data_view d -- ~10 million rows in this view
where d.organization_id = any (%L) -- array_a: 4 values in int[]
and d.element_id = any (%L) -- array_b: ~10,000 values in int[]
)
select c.*, c.value, d.value, r.value, s.value
from (select * from data where data.population = ''C'') c -- this reduces rows down to ~1000
left join (select * from data where data.population = ''D'') d on d.common_id = c.common_id
left join (select * from data where data.population = ''R'') r on r.common_id = c.common_id
left join (select * from data where data.population = ''S'') s on s.common_id = c.common_id
', array_a, array_b);
工作得很好!