Будет ли Postgres вычислять вычисляемые столбцы, которые не выбраны в представлении?

8

Я пытаюсь понять влияние на производительность выбора данных из представления, где один из столбцов в представлении является функцией других данных в исходной таблице.

Выполняются ли вычисления независимо от того, находится ли вычисляемый столбец в списке выбранных столбцов?

Если бы у меня был стол и вид объявлен так

CREATE TABLE price_data (
    ticker     text,          -- Ticker of the stock
    ddate      date,          -- Date for this price
    price      float8,        -- Closing price on this date
    factor     float8         -- Factor to convert this price to USD
);

CREATE VIEW prices AS 
    SELECT ticker, 
           ddate,
           price,
           factor,
           price * factor as price_usd
    FROM price_data

Будет ли это умножение выполняться в запросе, подобном приведенному ниже?

select ticker, ddate, price, factor from prices

Есть ли ссылка, которая гарантирует это так или иначе? Я читал документацию по системе правил в Postgres, но я думаю, что ответ на самом деле лежит на оптимизаторе, поскольку ничто в документации системы правил не указывало, что он не будет выбран.

Я подозреваю, что в приведенном выше случае вычисления не выполняются. Я изменил взгляд на использование деление вместо умножения и вставил 0на factorв price_data. Приведенный выше запрос не дал сбоя, но если запрос был изменен для выбора вычисляемого столбца, измененный запрос не выполнен.

Есть ли способ понять, какие вычисления выполняются, когда selectвыполняется? Я думаю, что я ищу что-то вроде, EXPLAINно это также говорит мне о вычислениях, которые выполняются.

Варун Мадиаф
источник
1
Это отличный вопрос, который мы хотели бы поддержать на этом SE
Гай

Ответы:

6

Как сказал @Laurenz, ваш анализ верен: оптимизатор будет избегать оценки выражений столбцов, которые не влияют на результат запроса (и ваша попытка вызвать ошибку деления на ноль является доказательством этого).

Это зависит от того, какие столбцы вы выбираете, но также зависит от категории волатильности выражений столбцов. Оптимизатор может свободно опускать immutableи вызывать stableфункции, если их выходные данные никогда не используются, поскольку они не могут повлиять на результат, но volatileфункции могут иметь побочные эффекты, поэтому их не так легко оптимизировать.

Например:

create function stable_function() returns int as $$
begin
  raise notice 'stable_function() called';
  return 1;
end
$$
language plpgsql stable;

create function volatile_function() returns int as $$
begin
  raise notice 'volatile_function() called';
  return 1;
end
$$
language plpgsql volatile;

create view v as
  select stable_function(), volatile_function();

Если volatileвыбран только столбец:

test=# explain (analyse, verbose) select volatile_function from v;
NOTICE:  volatile_function() called
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Subquery Scan on v  (cost=0.00..0.27 rows=1 width=4) (actual time=0.057..0.057 rows=1 loops=1)
   Output: v.volatile_function
   ->  Result  (cost=0.00..0.26 rows=1 width=8) (actual time=0.056..0.056 rows=1 loops=1)
         Output: NULL::integer, volatile_function()

... тогда, как вы можете видеть, stable_function()отсутствует на explainвыходе, и отсутствие NOTICEподтверждения подтверждает, что этот вызов был оптимизирован.

Однако, если stableвместо этого выбран столбец:

test=# explain (analyse, verbose) select stable_function from v;
NOTICE:  stable_function() called
NOTICE:  volatile_function() called
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Subquery Scan on v  (cost=0.00..0.52 rows=1 width=4) (actual time=0.139..0.139 rows=1 loops=1)
   Output: v.stable_function
   ->  Result  (cost=0.00..0.51 rows=1 width=8) (actual time=0.138..0.138 rows=1 loops=1)
         Output: stable_function(), volatile_function()

... тогда мы видим, как оба выражения столбца появляются в плане, и NOTICEs показывают, что обе функции были выполнены.

Похоже, в документах нет явного упоминания об этом поведении, поэтому нет никаких твердых гарантий относительно того, будет ли выражение оцениваться, и вы не должны полагаться на какие-либо побочные эффекты, которые могут иметь ваши вызовы функций.

Но если ваша единственная забота - это производительность, то, пока вы помечаете свои функции как stableили immutableгде это уместно, вы можете быть достаточно уверены (особенно в таких простых случаях, как этот), что они не будут оцениваться, если они не нужны.

(И пока вы там проверяете свои декларации волатильности, вы можете также установить параллельные флаги безопасности .)

Ник Барнс
источник
1
«поэтому он будет вызываться независимо». Он будет вызываться в соответствии с конкретными гарантиями СУБД. Из которых не может быть ни одного. Запрос SQL описывает результат, а не процесс. Документация PostgesSQL является ВОЛАТИЛЬНОЙ: оптимизатор не делает никаких предположений о поведении таких функций. Запрос, использующий энергозависимую функцию, пересмотрит функцию в каждой строке, где необходимо ее значение. (Все, что "нужно" означает.)
philipxy
@philipxy: Ты абсолютно прав. Я не хотел подразумевать каких-либо гарантий, помимо тех, которые указаны в документации, хотя при повторном чтении я, конечно, сделал. Надеюсь, моя редакция проясняет ситуацию. Спасибо!
Ник Барнс
4

Ваше подозрение верно, и вычисление не должно выполняться, если столбец не используется.

Чтобы подтвердить это, посмотрите на вывод EXPLAIN (VERBOSE)запроса, который покажет вам возвращенные столбцы.

Лоренц Альбе
источник