Skip to content

Workaround для MariaDB ​

Разбор задачи, где нужно было реализовать логику, обычно решаемую через оконные функции, в условиях ограничений версии MariaDB, где ROW_NUMBER() ещё не поддерживался.

Задача ​

Построить статистический отчёт по максимальному количеству:

  • одновременных конференций;
  • одновременных пользователей;
  • значений с разбивкой по дням и без нее.

Источник данных - события входа и выхода участников конференций из Openfire.

Контекст ​

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

В современной SQL-СУБД такую задачу удобно решать через оконные функции вроде ROW_NUMBER() и последующие вычисления поверх упорядоченного набора строк.

Проблема была в том, что используемая версия MariaDB таких функций еще не поддерживала. При этом:

  • обновление БД не входило в задачу;
  • менять внешнюю систему хранения было нежелательно;
  • отчет нужно было реализовать в существующей инфраструктуре.

Ограничение ​

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

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

  • устойчивую нумерацию строк в нужном порядке;
  • последующий расчет максимума по уже упорядоченной последовательности событий.

Решение ​

Вместо ROW_NUMBER() была сделана схема с временными таблицами.

Сначала формировалась промежуточная таблица с датами входа и выхода. Затем создавалась временная таблица ord_tmp, куда события старта интервалов записывались с AUTO_INCREMENT полем start_ordinal. По сути это и было заменой ROW_NUMBER() для стартовых событий.

Дальше:

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

На выходе получалась последовательность, над которой уже можно было считать максимум одновременных активных интервалов без оконных функций.

Ключевая идея алгоритма ​

Решение строилось вокруг того, что для каждого стартового события можно сохранить его порядковый номер, а затем после полной сортировки всех событий вычислить положение старта в общей последовательности.

Дальше максимум считался формулой:

MAX(2 * start_ordinal - start_or_end_ordinal)

Это позволяло получить максимальное количество одновременно активных интервалов:

  • для конференций;
  • для пользователей;
  • как за весь период, так и по дням.

Фактически удалось вручную воспроизвести поведение, которое в более новых версиях SQL обычно решается оконной аналитикой.

Почему это было хорошим решением ​

Решение дало практический результат без рискованных инфраструктурных изменений:

  • без обновления версии MariaDB;
  • без переписывания хранилища;
  • без выноса расчета в отдельный сервис;
  • с повторным использованием одной и той же схемы для нескольких отчетов.

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

Результат ​

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

Это позволило:

  • реализовать нужные статистические отчеты в текущем стеке;
  • не блокироваться на ограничениях версии БД;
  • сохранить решение полностью внутри существующей системы.

См. также ​

Сайт обновлен и проверен: