PostgreSQL SQL函数比硬编码查询慢10倍

时间:2015-11-13 23:12:14

标签: postgresql

如果我将以下函数硬编码到查询中,它的处理速度要快10倍......关于如何使函数快速运行的任何想法?

我认为编写sql函数的一个优点是查询规划器在这些函数上完全正常运行,与PL语言函数形成对比。

顺便说一下,我正在使用PostgreSQL 9.4。

更新

我现在已经意识到执行速度差异不是来自于将查询放在函数中,而是我如何调用函数。

select * from spatial.aggregate_raster_stats_by_geom(155);>> 1.5秒

select (spatial.aggregate_raster_stats_by_geom(155)).*;>> 15秒

CREATE OR REPLACE FUNCTION spatial.aggregate_raster_stats_by_geom(
  IN arg_rid INTEGER
) 
-- This function is called by the trigger that is fired whenever an entry is created in the raster catalog.
RETURNS TABLE(band INTEGER,gid INTEGER, rid INTEGER, product_id INTEGER,ref_datetime TIMESTAMP ,scale INTEGER, count BIGINT, sum FLOAT, mean FLOAT, stddev FLOAT, min FLOAT, max FLOAT) AS
$$
SELECT
    band,
    gid,
    arg_rid as rid,
    product_id,
    ref_datetime,
    scale,
    (ST_SummaryStats(clip,band,TRUE)).* -- compute summary statistics (min and max, etc are also in there). TRUE indicates that nodata should be ignored.
    FROM
      (SELECT
        gid,
        ST_Union(ST_Clip(rast, geom)) as clip -- assemble the raster tiles and clip them with the assembled polygons
      FROM 
        spatial.raster_tiles AS r
      JOIN 
        spatial.geom_catalog AS polygons
        ON ST_Intersects(rast,polygons.geom) -- only select raster tiles that touch the polygons. Spatial indexes should make this fast
      JOIN
        spatial.geom_metadata AS geometa
        ON geometa.product_id = polygons.product_id
      WHERE 
        geometa.aggregate_raster_auto = TRUE
        AND r.rid=$1

      GROUP by gid
      ) as foo
    cross join (
    -- Join bands to the selection
    -- this join has to be introduced AFTER the clipping. If done before, then clipping will be performed for each band.
        SELECT 
          generate_series(md.band_data_start,band_count) as band,
          data_scale_factor as scale,
          md.product_id,
          rid, 
          ref_datetime
        FROM spatial.raster_metadata md 
       JOIN spatial.raster_catalog rst ON rst.product_id = md.product_id
       WHERE rst.rid = $1) AS bar2
$$
  LANGUAGE sql IMMUTABLE;

1 个答案:

答案 0 :(得分:0)

阿。你遗漏了关键细节。

在PostgreSQL中(至少在9.5岁及以上)写作:

SELECT ( f () ).*;

...为每个结果列运行f一次!

这基本上是一次宏观扩张。

要解决它,请在另一层子查询中进行换行。