我正在尝试使用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
我不想为ST_SnapToGrid
和x
重新计算y
。所以我把它改为使用子查询:
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()
的结果值吗?
如果没有,有没有办法让它做到这一点?
答案 0 :(得分:2)
您没有在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
而不是:
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 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 ANALYZE
或EXPLAIN (ANALYZE, TIMING OFF)
对所有三项进行测试,并亲眼看看。测试>>猜测。