Повторно использовать вычисленное значение выбора

Я пытаюсь использовать ST_SnapToGrid, а затем GROUP BY ячейки сетки (х, у). Вот что я сделал первым:

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()?
Если нет, есть ли способ заставить это сделать это?

1 ответ

Решение

Время тестирования

Вы не видите оценку отдельных функций в строке в EXPLAIN выход.

Тест с EXPLAIN ANALYZE чтобы получить фактическое время запроса для сравнения общей эффективности. Запустите пару раз, чтобы исключить артефакты кэширования. Для простых запросов, подобных этому, вы получите более надежные числа для общего времени выполнения с помощью:

EXPLAIN (ANALYZE, TIMING OFF) SELECT ...

Требуется Postgres 9.2+. По документации:

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) и убедитесь сами. Тестирование >> гадание.

Другие вопросы по тегам