Предыстория

Бурное развитие технологий значительно изменило отрасль разработки приложений.
За последние годы изменился не только мир разработки корпоративного ПО (enterprise), но и его конечный потребитель. Сегодня потребитель enterprise-приложений («Заказчик») хочет использовать новые технологии, уделяет повышенное внимание UI/UX, пробует решать масштабные задачи «бесшовного» функционального взаимодействия различного ПО, задачи автоматизации сопровождения сложных IT-ландшафтов, развертывания, машинного обучения и т. д.

При этом российский заказчик действует в рамках ограничений. Прежде всего, это риски, связанные с зависимостью от иностранных компаний в части ключевых элементов IT-ландшафтов: иностранные коммерческие СУБД, которые используют важные для бизнеса enterprise-приложения. Для некоторых заказчиков независимость СУБД является одним из важнейших критериев при принятии решения о замене существующего ПО или внедрении нового.

Развитие технологий предоставляет командам разработчиков широкий выбор свободно распространяемых независимых платформ, фреймворков, СУБД и компонентов с открытым кодом для реализации enterprise-приложений.
То есть, у современных разработчиков enterprise-приложений есть возможности для решения проблемы зависимости от иностранных производителей СУБД.

Ещё десять лет назад выбор СУБД был значительно меньшим. При этом, помимо плюсов и минусов самих СУБД, необходимо было ориентироваться на заказчиков и их предпочтения. Тогда мало кто из разработчиков enterprise-приложений руководствовался database-agnostic принципом при разработке, поскольку такая реализация сложнее, а конечные заказчики не видели очевидных бизнес-преимуществ в использовании такой архитектуры.

Сегодня типичное «зрелое» enterprise-приложение содержит существенную часть логики на уровне БД. При этом со временем, стараясь сделать продукт лучше, разработчики усиливали связь с СУБД, используя различные специфичные особенности диалектов SQL и БД-специфичные настройки, усложняя при этом себе задачу по поддержанию нескольких БД.

Опыт нашей компании

В 2014 году компания «НВ-АСУпроект» столкнулась с задачей перевода enterprise-системы OIS iField с СУБД Oracle на СУБД SAP HANA. Предвидя сложности с поддержкой двух версий бизнес-логики СУБД, архитекторы «НВ-АСУпроект» приняли решение о применении database-agnostic принципа за счёт приведения SQL-логики к стандарту ANSI SQL в тех случаях, где это возможно.

После серии экспериментов с SAP HANA стало очевидным, что основной проблемой перевода приложения на SAP HANA является непредсказуемость трудоёмкости переноса исполняемой логики на SAP HANA. Это связанно как с особенностями диалекта SAP HANA, так и с особенностями работы оптимизатора по выполнению запросов. Встреченные проблемы могли отразиться на всём объёме логики приложения, реализованного на уровне БД, и вылиться в тысячи человеко-часов. Тем не менее задачу удалось решить примерно за полгода усилиями командой из 5 человек.

В результате в приложении выделился дополнительный метаслой доступа к данным, реализована GUI-среда для управления запросами и достигнута «кросcплатформенность» (с точки зрения СУБД). Команда разработки достигла того уровня компетенций, который позволил им начать применять database-agnostic принцип, и OIS iField был выпущен под брендом SAP UFAM.

Следующим вызовом для команды разработки OIS iField стала поддержка некоммерческой свободно распространяемой СУБД PostgreSQL. Несмотря на реализованную поддержку разных СУБД со стороны ПО, риски и неопределенность в отношении перевода части логики приложения на PostgreSQL сохранились.

Цель этой статьи заключается в том, чтобы на частном примере развеять некоторые мифы (и выявить некоторые подводные камни) о проблемах, связанных  с переводом логики БД на PostgreSQL.

Ожидания vs. реальность

«Большие сложные» запросы будут работать медленнее, что потребует их переписывания

В реальности в standard edition не поддерживается механизм хинтов. Long running operations пришлось обрабатывать поштучно. Отсутствие механизма неявного приведения типов значительно замедлило переход на PostgreSQL.

PostgreSQL нестандартно работает со стандартными механизмами других СУБД (триггеры/вью/процедуры/функции)

На самом деле все стандартные механизмы работают идентично с Oracle и SAP HANA. Неожиданностью оказалось то, что анонимные блоки не возвращают результат стандартным способом (через return) — только через out-параметры в функциях. Чтобы решить проблему пришлось реализовывать механизм динамического создания функций, что значительно усложнило логику и понизило сопровождаемость.

Механизмы СУБД Oracle и SAP HANA позволяют достичь достаточной продуктивности для работы бизнес-пользователей. Производительность PostgreSQL под такой нагрузкой в аналогичном hardware-окружении будет значительно ниже

В нашем случае PostgreSQL показал результаты по производительности, сопоставимые с Oracle и SAP HANA. Судя по всему, значительная разница в производительности проявляется при использовании PostgreSQL для высоконагруженных highload-систем.

Механизм работы с индексами таблиц PostgreSQL аналогичен механизмам СУБД Oracle, SAP HANA и MSSQL

В действительности PostgreSQL имеет некоторые особенности работы с индексами. Например, в частичных индексах из-за специфики их работы с null (в отличие от Oracle , PostgreSQL не отрабатывает уникальное ограничение, если одно или более полей в уникальном ключе равно NULL) в секции ‘on conflict on constraint’ пришлось создавать специальную функцию на уровне БД.

Работа с транзакциями в PostgreSQL аналогична другим СУБД. При реализации поддержки PostgreSQL не придётся переписывать логику работы внутри транзакций

Было выявлено весьма специфичное поведение PostgreSQL: если одна из команд транзакции возвращает ошибку, остальные команды игнорируются. Наше решение — запоминать состояние транзакции и откатываться в случае ошибки.

Обращение к объектам БД по умолчанию нечувствительно к регистру

В реальности идентификатор, заключённый в кавычки, становится зависимым от регистра, тогда как идентификаторы без кавычек всегда переводятся в нижний регистр. Пришлось проводить нормализацию переменных, названий колонок и таблиц.

Для повторения всех объектов БД Oracle в PostgreSQL придётся выполнять скрипты для каждого объекта БД

Сторонняя утилита OraToPG автоматически генерирует скрипты создания объектов БД, что упрощает самый первый перенос из Oracle в PostgreSQL.

PostgreSQL поддерживает merge

В реальных условиях для реализации логики merge пришлось использовать специфические конструкции (insert on conflict).

Аналогично другим СУБД, возможности СУБД определяются прежде всего её версией

Возможности установленной СУБД PostgreSQL могут быть значительно расширены за счёт сторонних расширений (extensions).

Заключение

Конечно, опыт команды «НВ-АСУпроект» по переводу enterprise-приложения на СУБД PostgreSQL является субъективным. Также как и опыт любой другой отдельно взятой команды. Однако эта заметка может помочь командам снизить степень неопределенности перед началом работ по переносу логики БД в PostgreSQL и сконцентрироваться на некоторых моментах при подготовке проекта переноса. Обобщая наш опыт, поддержку PostgreSQL можно выполнить относительно малой кровью при соблюдении следующих условий:

  • Проведение предварительных работ по аудиту архитектуры (возможно перераспределение логики с БД на уровень приложения);
  • Наличие ресурсов «с запасом» для этого проекта (могут возникнуть неожиданные затраты на переписывание запросов);
  • Привлечение DevOps, которые для каждого «тяжелого» запроса будут проводить нагрузочные тесты и выполнять тюнинг запросов.

Таким образом, реализация поддержки PostgreSQL — вполне посильная задача даже для небольших команд. Более того, современная ситуация на рынке российского enterprise-ПО делает эту задачу очень актуальной.