Меня интересует падение производительности, когда простая функция 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 .
Но я не совсем уверен, как это могло быть объяснением. Как не встраивание функции может привести к падению производительности в этом простом сценарии? Без индекса, без чтения с диска, без сортировки. Может быть, накладные расходы из-за повторяющегося вызова функции упрощаются путем встраивания функции? Вы можете это объяснить? Или мне что-то не хватает?
Тот же тест на том же оборудовании с 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 (!!!)
Тот же тест на другом оборудовании с 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 (!!!)