Различие SQL, PL/pgSQL, PL/Python

Статья основана на третьем видео из 30 тем курса SQL 2.0 — PL/pgSQL в PostgreSQL от Аристова Евгения, который является логическим продолжением курса SQL c 0. Ссылки на видео на платформах RUTUBE и VK видео.

В данной статье подробно разбирается разница между языками SQL, PL/pgSQL, PL/Python, их плюсы и минусы при программировании.

В прошлой статье мы разобрали структуру функции в PostgreSQL.

Презентация и исходники доступны по ссылке.

Язык PL/PgSQL

Несмотря на то, что мы можем писать функции на чистом SQL, его функционал довольно ограничен и в PostgreSQL был придуман язык PL/pgSQL.

Основные цели загружаемого процедурного языка:

  • может выполнять сложные вычисления
  • используется для создания функций и триггеров
  • добавляет управляющие структуры к языку SQL
  • наследует все пользовательские типы, функции и операторы
  • прост в использовании

Функции PL/pgSQL могут использоваться везде, где допустимы встроенные функции. Также они могут вызываться и как источник записей в указании FROM.

В версии PostgreSQL 9 и выше, PL/pgSQL встроен по умолчанию, до этого его было необходимо устанавливать отдельно.

PL/pgSQL позволяет сгруппировать блок вычислений и последовательность запросов внутри сервера базы данных, таким образом, мы получаем силу процедурного языка и простоту использования SQL при значительной экономии накладных расходов на клиент-серверное взаимодействие.

Важные особенности:

  • Расширяется функционал простого SQL
  • Доступ к дополнительному, в т.ч. внешнему функционалу
  • Расширенные варианты возврата значений из функций
  • Промежуточные ненужные результаты не передаются между сервером и клиентом
  • Есть возможность избежать многочисленных разборов одного запроса

В результате это может привести к значительному увеличению производительности по сравнению с приложением, которое не использует хранимых функций. Кроме того, PL/pgSQL позволяет использовать все типы данных, операторы и функции SQL.

Особенности синтаксиса PL/PgSQL:

CREATE FUNCTION sales(total real) RETURNS real AS $$
BEGIN
RETURN (4 статья) total * 2;
END;
$$ LANGUAGE plpgsql;

Важно не путать использование BEGIN/END для группировки операторов в PL/pgSQL с одноимёнными SQL-командами для управления транзакциями (BEGIN/COMMIT/ROLLBACK).

BEGIN/END в PL/pgSQL служат только для группировки команд в блоки (6 тема курса); они не начинают и не заканчивают транзакции.

Разница SQL и PL/pgSQL.

SQL:

CREATE or REPLACE FUNCTION increment(integer) RETURNS integer
    AS $$ SELECT $1 + 1; $$
LANGUAGE SQL;

PL/pgSQL:

CREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$
BEGIN
    RETURN i + 1;
END;
$$ LANGUAGE plpgsql;

В PL/pgSQL добавляются команды BEGIN/END и применяется RETURN для возвращения значения из функции.

PL/Python

PL/Python — это процедурное расширение для PostgreSQL, которое позволяет писать функции, триггеры и процедуры на языке Python. Его использование оправдано в specific scenarios, где встроенные возможности SQL и PL/pgSQL недостаточны.

Ключевые причины использования PL/Python:

1. Доступ к богатой экосистеме Python

  • Библиотеки для Data Science: Интеграция с pandas, numpy, scikit-learn для сложной аналитики и ML прямо внутри БД.
  • Работа с данными: Использование json, xml, yaml парсеров для обработки сложных структур.
  • Сетевые возможности: Вызов API (requests), парсинг веб-страниц (BeautifulSoup), работа с сетевыми протоколами.
  • Системные вызовы: Взаимодействие с ОС (например, работа с файловой системой).

2. Сложные вычисления и алгоритмы

  • Машинное обучение: Обучение и применение моделей напрямую в БД (например, классификация данных в реальном времени).
  • Статистический анализ: Расчёты, которые сложно реализовать на SQL (например, регрессия, кластеризация).
  • Криптография: Хеширование, шифрование с использованием библиотек типа cryptography.

3. Интеграция с внешними системами

  • Веб-сервисы: Автоматическая отправка данных в CRM, ERP или другие системы через API.
  • Работа с очередями: Отправка задач в RabbitMQ, Kafka или Redis.
  • Нотификации: Отправка email (smtplib) или сообщений в Slack/Telegram через вебхуки.

4. Преобразование данных

  • Парсинг сложных форматов: Обработка нестандартных текстовых или бинарных данных.
  • Конвертация данных: Например, преобразование изображений в текстовое описание с помощью OCR (Tesseract).
  • Генерация контента: Создание отчетов в PDF, Excel или HTML прямо внутри БД.

5. Автоматизация административных задач

  • Кастомный мониторинг: Проверка состояния БД и отправка алертов.
  • Резервное копирование: Интеграция с облачными хранилищами (S3, Google Cloud Storage).
  • Динамическое управление: Изменение конфигураций БД на основе условий.

Примеры использования PL/Python:

  • Вызов внешнего API
CREATE FUNCTION get_currency_rate(currency VARCHAR)
RETURNS JSON
AS $$
     import requests
     response = requests.get(f'https://api.exchangerate.host/     latest?base={currency}')
     return response.json()
$$ LANGUAGE plpython3u;
  • Работа с файловой системой
CREATE FUNCTION read_logs(log_path VARCHAR)
RETURNS TEXT[]
AS $$
     with open(log_path, 'r') as f:
     return f.readlines()
$$ LANGUAGE plpython3u;
  • Классификация текста с помощью ML
CREATE FUNCTION classify_text(text TEXT)
RETURNS VARCHAR
AS $$
     import pickle
     model = pickle.load(open('/models/text_classifier.pkl', 'rb'))
     return model.predict([text])[0]
$$ LANGUAGE plpython3u;

Ограничения и риски

Безопасность:

  • Используйте только plpython3u (untrusted), если нет полного доверия к пользователям.
  • Риск выполнения опасного кода (например, системных вызовов).

Производительность:

  • Запуск Python-кода требует больше ресурсов, чем нативный SQL.
  • Не подходит для высоконагруженных OLTP-операций.

Зависимости:

  • Необходимость установки Python-библиотек на сервере БД.
  • Совместимость версий Python и библиотек.

Переносимость:

  • Привязка к PostgreSQL и конкретной версии Python.

Если сравнивать PL/Python и PL/pgSQL, то при работе непосредственно с данными, он с высокой долей вероятности будет работать медленнее.

Например цикл в 1 млн.итераций на PL/pgSQL:

DO $$
    DECLARE a int; i int;
    BEGIN FOR i IN 0..99999 LOOP
          SELECT count(*) INTO a FROM pg_class;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Время выполнения около 3 секунд.

Для 1 млн. запросов: 35 секунд.


На PL/Python:

DO $$
     for i in range (0,100000) :
          plpy.execute('SELECT count(*) FROM pg_class')
$$ LANGUAGE plpython3u;

Время выполнения около 5 секунд.

Для 1 млн. запросов: 55 секунд.

Но мы можем ускорить этот вариант, используя подготовленные запросы, чтобы не нужно было каждый раз строить план выполнения:

DO $$
h = plpy.prepare('SELECT count(*) FROM pg_class')
for i in range (0,100_000):
plpy.execute(h)
$$ LANGUAGE plpython3u;

Время выполнения около 4 секунд.

Для 1 млн запросов: 42 секунд.

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


Опубликовано

в

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

два × три =