do $$ declare tt integer[]; minRowNum integer; maxRowNum integer; MIN_TEMS constant integer := 1; MAX_TEMS constant integer := 15; LAST_ARR_IDX constant integer := MAX_TEMS * 2; NUM_FILAS constant integer := 1000; begin create temp table NTematica(rownum,tematica_id) as select S.n,(S.n * 841)::integer from generate_series(1,357) S(n); select min(X.rownum),max(X.rownum) into minRowNum,maxRowNum from NTematica X; prepare selectTematicasPlan(integer,integer,integer) as select array_agg(X.tematica_id) from NTematica X where X.rownum in ( select trunc(random() * ($2 - $1 + 1) + $1) :: integer from generate_series($3,trunc(random() * ($4 - $3 + 1) + $3) :: integer) ); for i in 1..NUM_FILAS loop execute selectTematicasPlan(minRowNum,maxRowNum,MIN_TEMS,MAX_TEMS); raise notice 'First is % and % are the others',tt[1],tt[2:LAST_ARR_IDX]; end loop; drop table NTematica cascade; deallocate selectTematicasPlan; end$$;
然后,执行失败并出现错误:
ERROR: Syntax error at or near "(" LINE 34: tt := execute selectTematicasPlan(minRowNum,maxRowNum...
然后,为了测试,我消除了“tt:=”并使用此结果再次运行它:
ERROR: function selecttematicasplan(integer,integer) does not exist LINE 1: SELECT selectTematicasPlan(minRowNum,M... ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts.
更新:
在此先感谢大家.我要澄清一些问题:
我的初始代码是“从select中插入”(包括CTE)以填充包含1000万条记录的表.我可以确认它非常慢.因此,我决定选择一个IMPERATIVE解决方案:创建一个索引的未记录表(像地图数据结构一样工作)并循环1000万次以“执行”数据“选择”从“地图”跟随“插入”数据.我将循环的“select”和“insert”拉出到预准备语句中,因为这样可以避免1000个解析工作到PG.发布的代码仅涉及我准备好的陈述的问题.
是否可以在pl / pgsql代码块中使用“prepare”“execute”? PG doc(http://www.postgresql.org/docs/9.4/static/sql-prepare.html,http://www.postgresql.org/docs/9.4/static/sql-execute.html)没有谈论(反对或赞成)pl / pgsql.
注意:我的数据库版本(“select version()”)是:
在x86_64-unknown-linux-gnu上的Postgresql 9.4.4,由gcc编译(Ubuntu 4.9.2-10ubuntu13)4.9.2,64位
解决方法
As each expression and sql command is first executed in the function,the PL/pgsql interpreter parses and analyzes the command to create a prepared statement
简而言之:在plpgsql代码块中显式创建预准备语句,然后动态执行该预准备语句是无用且低效且在概念上存在缺陷.
您要做的是准备一个语句,然后由后端准备该准备,然后您动态执行执行预准备语句的语句.这里没有讽刺意味:这就是发生的事情.另请注意,PL / pgsql EXECUTE语句无任何缓存:sql语句EXECUTE selectTematicasPlan(minRowNum,MAX_TEMS)在每次调用时都会被解析.这是一个相当简单的陈述,但是(如在Klin’s answer中)参数值必须每次都传递,即使它们在每次调用时都是相同的.我希望你能看到这种方法的低效率(如果没有,我会休息一下).
回到你的例子,你的功能应该是这样的:
DO $$ DECLARE tt integer[]; minRowNum integer := 1; maxRowNum integer := 357; MIN_TEMS constant integer := 1; MAX_TEMS constant integer := 15; NUM_FILAS constant integer := 1000; BEGIN CREATE TEMP TABLE NTematica(rownum,tematica_id) AS SELECT S.n,(S.n * 841)::integer FROM generate_series(minRowNum,maxRowNum) S(n); -- generate_series() produces numbers from the first parameter to the last,inclusive -- no need to query for those valuesselect min(X.rownum),maxRowNum from NTematica X;FOR i IN 1..NUM_FILAS LOOP SELECT array_agg(X.tematica_id) INTO tt FROM NTematica X WHERE X.rownum IN ( SELECT trunc(random() * (maxRowNum - minRowNum + 1) + minRowNum)::integer FROM generate_series(MIN_TEMS,trunc(random() * (MAX_TEMS - MIN_TEMS + 1) + MIN_TEMS)::integer) ); RAISE NOTICE 'First is % and % are the others',tt[2:array_upper(tt)]; END LOOP; DROP TABLE NTematica; END; $$;
您还可以将匿名代码块编写为单个sql语句,此处使用CTE来提高可读性:
WITH params(minRowNum integer,maxRowNum integer,MIN_TEMS integer,MAX_TEMS integer) AS SELECT 1,357,1,15 ),rowNums(rwNum integer,tematica_id integer) AS ( SELECT S.n,(S.n * 841)::integer FROM params,generate_series(params.minRowNum,params.maxRowNum) S(n) ) SELECT tt[1] AS first,tt[2:array_upper(tt)] AS rest FROM generate_series(1,1000) ON true JOIN ( SELECT array_agg(rw.tematica_id) AS tt FROM params p,rowNums rw WHERE rw.rwNum IN ( SELECT trunc(random() * (p.maxRowNum - p.minRowNum + 1) + p.minRowNum)::integer FROM generate_series(p.MIN_TEMS,trunc(random() * (p.MAX_TEMS - p.MIN_TEMS + 1) + p.MIN_TEMS)::integer) ) agg ON true;
多次使用的参数都在顶行,因此易于修改,不存在不一致的风险.这应该比匿名代码块快得多,因为你会丢失很多开销,尤其是在TEMP TABLE上.显然,您将获得结果作为常规表格数据,而不是1,000条通知.