Функция выполняется быстрее без модификатора STRICT?

Меня интересует падение производительности, когда простая функция SQL объявляется STRICT . Я наткнулся на это явление, когда отвечал на вопрос здесь .

Чтобы продемонстрировать эффект, я создаю два варианта простой функции SQL, которая упорядочивает два элемента массива в порядке возрастания.

Тестовая установка

-- temporary table with 10000 random pairs of integer
CREATE TEMP TABLE arr (i int[]);

INSERT INTO arr 
SELECT ARRAY[(random() * 1000)::int, (random() * 1000)::int]
FROM   generate_series(1,10000);

Функция с модификатором STRICT :

CREATE OR REPLACE FUNCTION f_sort_array1(int[])  RETURNS int[] AS
$$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$$ LANGUAGE sql STRICT IMMUTABLE;

Функция без модификатора STRICT (в остальном идентична):

CREATE OR REPLACE FUNCTION f_sort_array2(int[])  RETURNS int[] AS
$$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$$ LANGUAGE sql IMMUTABLE;

Результаты

Я выполнил каждую примерно по 20 раз и взял лучший результат из EXPLAIN ANALYZE .

SELECT f_sort_array1(i) FROM arr;  -- Total runtime: 103 ms
SELECT f_sort_array2(i) FROM arr;  -- Total runtime:  43 ms (!!!)

Это результаты сервера v9.0.5 на Debian Squeeze. Аналогичные результаты на v8.4. Не тестировал на 9.1, сейчас в моем распоряжении нет кластера. (Может ли кто-нибудь предоставить дополнительные результаты для v9.1?)

Редактировать: В тесте с 10000 значениями NULL обе функции выполняются одинаково в одной и той же тестовой среде: ~ 37 мс.

Я провел небольшое исследование и обнаружил интересную ошибку.Объявление функции SQL STRICT в большинстве случаев отключает встраивание функций . Подробнее об этом в онлайн-журнале PostgreSQL , в списке рассылки pgsql-performance или в Postgres Wiki .

Но я не совсем уверен, как это могло быть объяснением. Как не встраивание функции может привести к падению производительности в этом простом сценарии? Без индекса, без чтения с диска, без сортировки. Может быть, накладные расходы из-за повторяющегося вызова функции упрощаются путем встраивания функции? Вы можете это объяснить? Или мне что-то не хватает?


Повторное тестирование с Postgres 9.1

Тот же тест на том же оборудовании с PostgreSQL 9.1, но обнаружены еще большие различия:

SELECT f_sort_array1(i) FROM arr;  -- Total runtime: 107 ms
SELECT f_sort_array2(i) FROM arr;  -- Total runtime:  27 ms (!!!)

Повторное тестирование с Postgres 9.6

Тот же тест на другом оборудовании с PostgreSQL 9.6. Но разрыв еще больше:

SELECT f_sort_array1(i) FROM arr;  -- Total runtime: 60 ms
SELECT f_sort_array2(i) FROM arr;  -- Total runtime: 10 ms (!!!)

6
задан Erwin Brandstetter 5 June 2017 в 19:26
поделиться