Почему функции PL / pgSQL могут иметь побочный эффект, а функции SQL - нет? - PullRequest
0 голосов
/ 23 июня 2018

Документ PostgreSQL гласит:

Все тело функции SQL анализируется перед выполнением любой из них. Хотя функция SQL может содержать Команды, которые изменяют системные каталоги (например, CREATE TABLE), эффекты таких команд не будут видны во время анализа анализа более поздних команд в функции.Так, например, CREATE TABLE foo (...); INSERT INTO foo VALUES(...); не будет работать должным образом, если он упакован в одну функцию SQL , поскольку foo еще не будет существовать, когда команда INSERT будет проанализирована.

В этом типе ситуации рекомендуется использовать PL / pgSQL вместо функции SQL.

  • Почему "Рекомендуетсяиспользуйте PL / pgSQL вместо функции SQL в такой ситуации ", где функция PL / pgSQL или SQL содержит команды, которые изменяют системные каталоги, такие как CREATE TABLE foo (...); INSERT INTO foo VALUES(...);?

  • Msgstr "Все тело функции SQL анализируется перед выполнением любой из них".Разве это не верно для функции PL / pgSQL?Какие различия между функциями SQL и функциями PL / pgSQL с точки зрения разбора и выполнения команд в их теле?

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

Вы сами набрали ключевое предложение в руководстве сами:

Все тело функции SQL анализируется перед выполнением любой из них.

Также читайте о Этап парсера в руководстве .

Он состоит из двух основных частей: парсер и процесс преобразования . Цитирование руководства:

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

Если функция SQL содержит следующие команды:

CREATE TABLE foo (...);
INSERT INTO foo VALUES(...);

Оба оператора планируются практически в одно и то же время (на основе одного и того же снимка системных каталогов). Следовательно, INSERT не может видеть таблицу "foo", предположительно созданную с помощью предыдущей команды CREATE. Это создает одну из следующих проблем :

  1. Если в вашем search_patch (пока что) нет таблицы other с именем "foo" (пока), Postgres жалуется при попытке создать функция:

    ERROR:  relation "foo" does not exist
    
  2. Если в вашем search_patch уже существует другая таблица с именем "foo" (и вы не используете конфликтующие имена столбцов), Postgres планирует INSERT на основе этой ранее существующей таблицы. Обычно это приводит к ошибке во время выполнения , если какие-либо значения вызывают конфликты в (неправильной!) Таблице. Или, если повезет, он может даже записать в эту таблицу без сообщения об ошибке! Очень подлый баг.

Этого не может быть с PL / pgSQL функцией, потому что она обрабатывает команды SQL как подготовленные операторы, запланированные и выполненные последовательно . Таким образом, каждый оператор может видеть объекты, созданные в предыдущих операторах.

Следовательно, операторы, которые никогда не посещаются, никогда даже не планируются - в отличие от функций SQL. И план выполнения для операторов может быть кэширован в том же сеансе - также в отличие от функций SQL. Подробнее о кэшировании плана в функциях PL / pgSQL см. Здесь.
Каждый подход имеет преимущества для некоторых случаев использования. Дальнейшее чтение:

0 голосов
/ 24 июня 2018

Функции Plpgsql анализируются и проверяются на синтаксис во время определения, а затем при первом выполнении генерируется план.

https://www.postgresql.org/docs/current/static/plpgsql-implementation.html#PLPGSQL-PLAN-CACHING

тогда этот план выполняется с заданными параметрами.

Кажется, что временные файлы работают должным образом, кроме тех, которые уже существуют при первом выполнении.

Как уже упоминалось, использование динамического SQL (EXECUTE) - это способ помешать планировщику, разрешив доступ к произвольным таблицам.

https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

...