【问题标题】:Reuse computed select value重用计算的选择值
【发布时间】:2014-03-18 18:15:39
【问题描述】:

我正在尝试使用ST_SnapToGrid 然后GROUP BY 网格单元(x,y)。这是我首先做的:

SELECT
  COUNT(*)                      AS n,
  ST_X(ST_SnapToGrid(geom, 50)) AS x,
  ST_Y(ST_SnapToGrid(geom, 50)) AS y
FROM points
GROUP BY x, y

我不想为xy 重新计算ST_SnapToGrid。所以我将其更改为使用子查询:

SELECT
  COUNT(*)   AS n,
  ST_X(geom) AS x,
  ST_Y(geom) AS y
FROM (
  SELECT 
      ST_SnapToGrid(geom, 50) AS geom
  FROM points
) AS tmp
GROUP BY x, y

但是当我运行EXPLAIN 时,这两个查询的执行计划完全相同:

GroupAggregate  (...)
  ->  Sort  (...)
        Sort Key: (st_x(st_snaptogrid(points.geom, 0::double precision))), (st_y(st_snaptogrid(points.geom, 0::double precision)))
        ->  Seq Scan on points  (...)

问题:PostgreSQL会复用ST_SnapToGrid()的结果值吗?
如果没有,有没有办法让它做到这一点?

【问题讨论】:

    标签: sql postgresql postgis explain postgresql-performance


    【解决方案1】:

    测试时机

    您在EXPLAIN 输出中看不到每行单个函数的评估。

    使用EXPLAIN ANALYZE 进行测试以获取实际查询时间以比较整体效果。运行几次以排除缓存工件。对于像这样的简单查询,您可以获得更可靠的总运行时间数字:

    EXPLAIN (ANALYZE, TIMING OFF) SELECT ...
    

    需要 Postgres 9.2+Per documentation:

    TIMING

    在输出中包含实际启动时间和在每个节点上花费的时间。重复读取系统时钟的开销可能会减慢 在某些系统上显着降低查询,因此可能有用 当只有实际行数时,将此参数设置为FALSE,而不是精确 次,需要。整个语句的运行时间总是 即使使用此选项关闭节点级时序也是如此。 该参数只能在ANALYZE 也启用时使用。它 默认为TRUE

    防止重复评估

    通常,子查询中的表达式被评估一次。但是如果 Postgres 认为这样会更快,它可以折叠琐碎的子查询。

    要引入优化障碍,您可以使用CTE 代替子查询。这保证 Postgres 只计算一次ST_SnapToGrid(geom, 50)

    WITH cte AS (
       SELECT ST_SnapToGrid(geom, 50) AS geom1
       FROM   points
       )
    SELECT COUNT(*)   AS n
         , ST_X(geom1) AS x
         , ST_Y(geom1) AS y
    FROM   cte
    GROUP  BY geom1;         -- see below
    

    但是,由于 CTE 的开销更大,这可能比子查询。函数调用可能非常便宜。通常,Postgres 更了解如何优化查询计划。只有在您了解得更多的情况下才引入这样的优化障碍。

    简化

    我将子查询/CTE 中计算点的名称更改为geom1,以说明它与原始geom 不同。这有助于澄清这里更重要的事情:

    GROUP BY geom1
    

    代替:

    <strike>GROUP BY x, y</strike>

    这显然更便宜 - 并且可能会影响函数调用是否重复。所以,这可能是最快的:

    SELECT COUNT(*) AS n
         , ST_X(ST_SnapToGrid(geom, 50)) AS x
         , ST_y(ST_SnapToGrid(geom, 50)) AS y
    FROM   points
    GROUP  BY ST_SnapToGrid(geom, 50);         -- same here!
    

    或者这样:

    SELECT COUNT(*)    AS n
         , ST_X(geom1) AS x
         , ST_y(geom1) AS y
    FROM (
       SELECT ST_SnapToGrid(geom, 50) AS geom1
       FROM   points
       ) AS tmp
    GROUP  BY geom1;
    

    使用EXPLAIN ANALYZEEXPLAIN (ANALYZE, TIMING OFF) 测试所有三个,然后自己看看。测试>>猜测。

    【讨论】:

      猜你喜欢
      • 2011-07-30
      • 2013-02-24
      • 2018-10-07
      • 2017-01-04
      • 2023-03-17
      • 2014-08-15
      • 2015-09-04
      • 2021-04-25
      • 1970-01-01
      相关资源
      最近更新 更多