«id =» main «> Поделиться

Недавно в списке рассылки Postgres появился интересный вопрос относительно возможности кэширования повторяющихся вычислений. Более того, на эту тему ответил неоспоримый авторитет: Том Лейн.

Чтобы проиллюстрировать проблему, был использован следующий запрос:

SELECT (a + b) * c AS c1, (a + b) * d AS d1, (a + b) * e AS e1 FROM table; < p> Для простоты сложный повторяющийся расчет был представлен как сложение двух значений a + b

Вопрос: Может ли Postgres распознавать и «кэшировать» повторяющиеся вычисления? Том Лейн: Нет.

Итак, что вы можете сделать, если предположить, что это выражение дорого? Как вы сообщите Postgres, что лучше сделать это один раз и передать результат? Несколько решений:

Может быть, лучше использовать подзапрос? Может быть, переписать его в CTE?

Объявление 1. Конструкция, аналогичная приведенному выше запросу с использованием подзапроса, будет выглядеть так:

SELECT x * c AS c1, x * d AS d1, x * e КАК e1 ИЗ (ВЫБРАТЬ a + b КАК x, * ИЗ таблицы) x;

Хотя наши вычисления появляются в логическом представлении только один раз, помните, что SQL — это декларативный язык, поэтому мы не можем предполагать, что движок сделает это один раз. Планировщик имеет право преобразовать их в любую форму, включая операцию, называемую «выравнивание». Это будет означать, что механизм преобразует запрос в его исходную форму, то есть заменяет перечисление в основном запросе псевдонимом в столбце. Этого не произойдет только в одном случае, если планировщик сочтет расчет «достаточно дорогим». Поэтому, если мы считаем, что расчет является дорогостоящим, и мы хотим избежать его выравнивания любой ценой, мы можем использовать для этой цели предложение OFFSET 0:

ВЫБЕРИТЕ x * c AS c1, x * d AS d1, x * e AS e1 FROM (SELECT a + b AS x, * FROM table OFFSET 0) x;

Обратите внимание, однако, что применение этого «взлома» не приведет к только отсутствие сглаживания означает, что планировщик отменяет все оптимизации, включая сглаживание. Так что, кстати, мы можем предотвратить гораздо более важную оптимизацию.

Ad. 2 Использование CTE, конструкции WITH, о которой я писал в предыдущей статье, было кратко прокомментировано Томом Лейном: это довольно грубый инструмент, стоимость которого может перевесить любые потенциальные выгоды.

Ну и что ты должен делать? Как подойти к проблеме? Решение, предложенное Томом Лейном, заключается в использовании предложения LATERAL:

SELECT x * c AS c1, x * d AS d1, x * e AS e1 FROM tab, LATERAL (SELECT a + b AS x OFFSET 0) ss;

Создание LATERAL соединения и подзапросов должно избежать большинства проблем оптимизации. За исключением одного: a + b будет выполняться для каждой строки в левой таблице («вкладка») независимо от того, требует ли данное использование значения из столбца x.

Rate this post