Повторно использовать вычисленное значение выбора
Я пытаюсь использовать 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)
и убедитесь сами. Тестирование >> гадание.