我正在尝试使用 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
我不想为 x
和 y
重新计算 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()
的结果值吗?
如果没有,有没有办法让它做到这一点?
最佳答案
测试时间
您不会在 EXPLAIN
输出中看到每行单个函数的评估。
使用 EXPLAIN ANALYZE
进行测试以获得实际查询时间以比较整体效率。运行几次以排除缓存工件。对于像这样的简单查询,您可以获得更可靠的总运行时间数字:
EXPLAIN (ANALYZE, TIMING OFF) SELECT ...
需要 Postgres 9.2+。 Per documentation :
TIMING
Include actual startup time and time spent in each node in the output. The overhead of repeatedly reading the system clock can slow down the query significantly on some systems, so it may be useful to set this parameter to
FALSE
when only actual row counts, and not exact times, are needed. Run time of the entire statement is always measured, even when node-level timing is turned off with this option. This parameter may only be used whenANALYZE
is also enabled. It defaults toTRUE
.
防止重复求值
通常,子查询中的表达式被计算一次。但是 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 ANALYZE
或 EXPLAIN (ANALYZE, TIMING OFF)
测试所有三个,然后自己看看。测试 >> 猜测。
关于sql - 重用计算的选择值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21863163/