Привет, Хабр! Пишет эту статью Александра Лысенко — вчера я была студенткой, а сегодня как инженер-программист Nexign спешу поделиться приобретенным опытом.

Мой первый проект для реального бизнеса был связан с миграцией с Oracle на PostgreSQL. Сегодня расскажу, как внедрение диапазонного типа данных при переходе между СУБД позволило не просто сохранить производительность, но и превзойти исходные показатели. Если вы тоже только начинаете свой карьерный путь — надеюсь, этот материал вам поможет.

Импортозамещение: не просто тренд, а необходимость.

С 2022 года импортозамещение в ИТ перестало быть абстрактной концепцией — оно стало необходимостью. Уход зарубежных вендоров и требования законодательства (в т.ч. указ Президента РФ № 166) подтолкнули Nexign и многие другие компании к переходу на отечественное ПО.

Особенно заметен рост числа решений на базе PostgreSQL: по данным независимого исследования ЛАНИТ, около 60 % отечественных СУБД используют именно эту платформу — речь идёт о российских системах управления базами данных, большинство из которых представляют собой доработанные версии открытого PostgreSQL. При этом миграция на такие решения — это не просто перенос бизнес‑логики и оперируемых данных: различия в архитектуре, диалектах SQL и поддерживаемых типах данных могут сыграть злую шутку.

Если производительность упала после миграции.

Моя команда столкнулась с проблемой при переносе биллинговой системы оператора связи с Oracle 19 на PostgreSQL 15.

На старте логическая и физическая структуры БД были идентичны — хотели получить «чистые» замеры. Для нагрузочного тестирования использовали Apache JMeter.

Условия теста:

  • 10 пользователей;

  • 5 категорий запросов (выборка актуальных тарифных планов, исторических данных и т. д.);

  • объём данных — 2 ГБ (на основе реальных обезличенных данных);

  • длительность теста — 60 секунд нагрузки, цикл повторялся 100 раз.

Первые результаты нас не порадовали:

  • среднее время выполнения запросов в PostgreSQL было сопоставимо с Oracle;

  • максимальное время выполнения выросло в 3–5 раз;

  • разброс значений времени выполнения запроса значительно увеличился.

Вывод был очевиден: прямая миграция без адаптации структуры базы данных приводит к деградации производительности.

Причина снижения производительности: работа с временными интервалами.

Биллинговые системы для поддержания рыночных бизнес-процессов оперируют хронологическими данными:

  • хранят исторические данные с периодами актуальности;

  • поддерживают ретарификацию (корректировку) прошлых периодов;

  • обрабатывают архивные тарифы для поддержания лояльности клиентов.

Традиционный подход в Oracle — хранить период актуальности в двух столбцах:

  • start_date (дата начала);

  • end_date (дата окончания).

Для выборки используют оператор BETWEEN и ограничения целостности (CONSTRAINT), что:

  1. усложняет запросы;

  2. повышает риск логических ошибок;

  3. возлагает всю ответственность на разработчика.

Решение: диапазонный тип данных PostgreSQL.

В PostgreSQL (начиная с версии 9.2) есть диапазонные типы (range types) — они позволяют хранить интервал как единое значение.

Ключевые преимущества:

  • встроенная поддержка операций с интервалами (пересечение, включение и т. д.);

  • возможность индексации (в т. ч. с помощью GIST-индексов);

  • поддержка бесконечности (∞) и исключённых границ;

  • операции основаны на интервальной алгебре Аллена.

При модификации физической модели БД:

  1. Заменили столбцы с периодом актуальности записи (start_date, end_date) на столбец диапазонного типа (validity).

  2. Создали GIST‑индекс для нового столбца для оптимизации запросов с фильтрацией данных по диапазонам.

Результат: производительность выросла в 2 раза

После внедрения диапазонных типов и GIST‑индексов провели повторное нагрузочное тестирование.

На выходе получили:

  • среднее время выполнения запросов сократилось в 2 раза;

  • разброс времени выполнения запросов значительно уменьшился;

  • показатели PostgreSQL превзошли результаты Oracle.

Почему так произошло:

  1. Упрощение запросов. Вместо сложных условий с BETWEEN и проверками границ — простые операции с диапазонами (например, @> для проверки включения).

  2. Эффективная индексация. GIST‑индекс ускоряет поиск по временным интервалам.

  3. Встроенные проверки. PostgreSQL автоматически контролирует корректность диапазонов (например, не допускает start_date > end_date).

Выводы и рекомендации для тех, кто на старте:

  • Не копируйте структуру «один в один». Миграция — повод пересмотреть архитектуру БД.

  • Используйте сильные стороны целевой СУБД. В PostgreSQL диапазонные типы — мощный инструмент для работы с хронологическими данными.

  • Тестируйте производительность. Нагрузочное тестирование до и после изменений — единственный способ оценить эффект.

  • Индексируйте разумно. GIST‑индексы отлично подходят для диапазонов, но требуют тестирования в контексте вашей нагрузки.

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

Итог: внедрение диапазонных типов данных — не просто «фишка» PostgreSQL, а реальный инструмент для повышения производительности. Если вы мигрируете с Oracle на PostgreSQL и работаете с хронологическими данными, обязательно рассмотрите этот подход. Он сэкономит вам время, нервы и ресурсы сервера.

Конечно, переход на диапазонные типы — не единственное архитектурное изменение, которое пришлось осуществить при смене СУБД. Мы столкнулись с массой других проблем, таких как: отсутствие пакетов процедур; отсутствие поддержки транзакций в функциях; массивов, индексируемых строками; logon триггеров; синонимов... Кажется, что этот список можно продолжать бесконечно, а как мы с этим боролись — предмет уже следующих статей :)

А как проходил ваш первый опыт оптимизации PostgreSQL? Делитесь в комментариях!

Комментарии (5)


  1. Akina
    26.06.2026 11:50

    Не, ну рассказ в стиле "автомобиль съехал с горки не быстрее велосипеда, а потом мы завелись...". Как по мне - вообще ни о чём, чисто ради плюсадина в публикации.


  1. baldr
    26.06.2026 11:50

    объём данных — 2 ГБ (на основе реальных обезличенных данных);

    В смысле вся база 2 ГБ? И запрос выполнялся 5 секунд? У меня возникают очевидные вопросы и получаются нехорошие выводы.


    1. PAL_habr
      26.06.2026 11:50

      Хотел спросить про то как делали и делали ли секционирование на этом добре, но 2гб пожалуй снимают вопрос. :)


  1. degvit
    26.06.2026 11:50

    По православному НТ проводить не менее 4 часов, а лучше длинным циклом 24-48 часов. Так вы сможете отследить не только SLA по выполняемым запросам, но и оценить утечки памяти и нагрузку на CPU.

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


  1. ptr128
    26.06.2026 11:50

    Самое непонятное, как же gist мог оказаться быстрей btree при работе с обычными диапазонами. Впрочем, так как в статье нет ни примера кода, ни результатов его модификации, ни бенчмарков, то речь может идти о каком-то хитром частном случае или кривых запросах из ORM.