PL/pgsql已经有不少优化动作,比如
- for i in 1..100000 loop
- null;
- end loop;
这是可以瞬间完成的。
对于调用次数很多的自定义函数,用C实现肯定比PL/pgsql快,但到底能快多少?
1、日期相加函数
- create function pl_tsadd(timestamp with time zone,text,int)
- returns timestamp with time zone as
- $$
- declare
- intv interval;
- begin
- if $2 = 'yyyy' then
- intv = '1 year'::interval * $3;
- elsif $2 = 'mm' then
- intv = '1 month'::interval * $3;
- elsif $2 = 'dd' then
- intv = '1 day'::interval * $3;
- else
- return null;
- end if;
- return $1 + intv;
- end;
- $$
- language plpgsql STRICT immutable;
逻辑很简单,参数1是被相加的值,参数2是代表单位的字符,参数3是数量
10万次调用
- for i in 1..100000 loop
- tmp = pl_tsadd(now(),'dd',i);
- end loop;
结果
- flying=# select plfunc();
- plfunc
- --------
- (1 row)
- Time: 320.965 ms
2、C语言实现同样逻辑
- PG_FUNCTION_INFO_V1(tsadd);
- Datum
- tsadd(PG_FUNCTION_ARGS)
- {
- Interval intv;
- Datum tsdatumin = PG_GETARG_DATUM(0);
- char *tspartnam = text_to_cstring(PG_GETARG_TEXT_PP(1));
- int32 tspartnum = PG_GETARG_INT32(2);
- memset(&intv,sizeof(intv));
- if (pg_strcasecmp(tspartnam,"yyyy")==0)
- {
- intv.month = tspartnum * 12;
- }
- else if (pg_strcasecmp(tspartnam,"mm")==0)
- {
- intv.month = tspartnum;
- }
- else if (pg_strcasecmp(tspartnam,"dd")==0)
- {
- intv.day = tspartnum;
- }
- else
- PG_RETURN_NULL();
- return DirectFunctionCall2(timestamptz_pl_interval,tsdatumin,IntervalPGetDatum(&intv));
- }
同样10万次
- flying=# select plfunc();
- plfunc
- --------
- (1 row)
- Time: 67.277 ms
可以看出,C实现确实比PL/pgsql快好几倍,但代码实现是有更大难度的。PL/pgsql执行一次的时间已经非常微小,除非有极大次数的反复调用,否则似乎意义不大。