powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Многократный вызов иммутабельной функции
3 сообщений из 3, страница 1 из 1
Многократный вызов иммутабельной функции
    #39773440
Фотография torbasow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть некая иммутабельная функция:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
CREATE OR REPLACE FUNCTION datamart.f_test (
  p_text text
)
RETURNS tsquery AS
$body$
SELECT plainto_tsquery('')
$body$
LANGUAGE 'sql'
IMMUTABLE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;



При её вызове база кидает нотайс:

NOTICE: text-search query doesn't contain lexemes: ""

Выполним вот такой запрос:

Код: sql
1.
2.
SELECT datamart.f_test('')::TEXT
FROM (VALUES ('aa'),('dd')) AS t



Две строки, но нотайс — поскольку функция иммутабельная, она вызвалась один раз.

Теперь вызовем этот же запрос, обёрнутый в другую функцию:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE OR REPLACE FUNCTION datamart.function (
  p1 text
)
RETURNS TABLE (
  f1 text
) AS
$body$
SELECT datamart.f_test($1)::TEXT
FROM (VALUES ('aa'),('dd')) AS t
$body$
LANGUAGE 'sql'
STABLE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100 ROWS 1000;



Выполняем:

Код: sql
1.
SELECT * FROM datamart.function ('')



Один нотайс.

А дальше начинаются странности: если мы делаем функцию-обёртку не STABLE или IMMUTABLE, а VOLATILE, иммутабельная функция изнутри неё вызывается дважды (что можно видеть по двум нотайсам), то есть по разу для каждой строчке. Почему? Функции-обёртке не всё равно? Она-то в любом случае вызывается один раз.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE OR REPLACE FUNCTION datamart.function (
  p1 text
)
RETURNS TABLE (
  f1 text
) AS
$body$
SELECT datamart.f_test($1)::TEXT
FROM (VALUES ('aa'),('dd')) AS t
$body$
LANGUAGE 'sql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100 ROWS 1000;



То же самое наблюдается, если мы задаём функции-обёртке опцию выполнения с привилегиями создателя (SECURITY DEFINER):

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE OR REPLACE FUNCTION datamart.function (
  p1 text
)
RETURNS TABLE (
  f1 text
) AS
$body$
SELECT datamart.f_test($1)::TEXT
FROM (VALUES ('aa'),('dd')) AS t
$body$
LANGUAGE 'sql'
STABLE
CALLED ON NULL INPUT
SECURITY DEFINER
COST 100 ROWS 1000;



Почему такое странное поведение?

Можно ли это преодолеть (хотя бы для случая SECURITY DEFINER)?

PostgreSQL 10.6
...
Рейтинг: 0 / 0
Многократный вызов иммутабельной функции
    #39773525
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
torbasowТеперь вызовем этот же запрос, обёрнутый в другую функцию:
Посмотрите на его explain и увидите, что планировщик вовсе выкинул функцию datamart.function и делал только голый запрос.
Другие два варианта sql inline нельзя.

В остальном поведение допустимое, immutable не гарантирует, что будет вызван единожды. immutable утверждает, что такое может быть на усмотрение базы. Почему внутри функции поведение отличается - у меня готового ответа нет. Может быть не сделали.
...
Рейтинг: 0 / 0
Многократный вызов иммутабельной функции
    #39774224
big-trot
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Если обертку переписать на plgslq, и в обертке использовать динамический SQL, то проблем таких не возникает.
Встает вопрос о целесообразности использовать sql функции, т.к. их поведение в не которых случаях непредсказуемо. В своей практике я с этим сталкиваюсь уже не первый раз.
Или как-то надо четко понимать, если логику можно реализовать как на sql-функциях, так и на plsql-функциях, как сделать правильный выбор, с точки зрения производительности.
...
Рейтинг: 0 / 0
3 сообщений из 3, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Многократный вызов иммутабельной функции
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]