sql - 重用计算的选择值

标签 sql postgresql postgis explain postgresql-performance

我正在尝试使用 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()的结果值吗?
如果没有,有没有办法让它做到这一点?

最佳答案

测试时间

您不会在 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 when ANALYZE is also enabled. It defaults to 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) 测试所有三个,然后自己看看。测试 >> 猜测。

关于sql - 重用计算的选择值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21863163/

相关文章:

mysql - 具有多个表连接的每个组的前 N ​​个

sql - SQL Server 2008-如何使用DELETE触发器更新字段

postgresql - 将数据加载到新 CitusDB 实例的最快方法是什么?

在 PostgreSQL 中进行全文搜索的 Django 模型架构

java - 如何使用 Java JDBCPreparedStatement 占位符将 GeoJSON 多边形插入 PostGIS 中?

postgresql - osm2pgsql : Function AddGeometryColumn doesn't exist

mysql - SQL 基于时间戳差异计算ON Multi table with multi condition - MySQL

python - SQLAlchemy:使用两个 MySQL 模式中的表进行查询

nhibernate - PostgreSQL 全文搜索与 NHibernate.Search 通过 Lucene.Net

python - 如何在 shapely 或类似的纯 python 库中运行 st_makevalid?