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

Проблемы

Меняющиеся атрибуты

Потребовалось сделать отчет по остаткам на лицевых счетах в биллинге на начало и конец каждого месяца. Данные идут в бухгалтерию.

Проблема — если мы относим договор к определённому нашему юридическому лицу (их несколько в биллинге), то в будущем, если атрибуты договора (вдруг по какой-либо причине) будут изменены, все его балансы за все периоды в прошлом будут отнесены к остаткам нового юридического лица и исключены из остатков старого.

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

Чтоб ответить на вопрос "почему изменились цифры?", нужно иметь возможность сопоставить атрибуты договоров до и после момента предоставления отчёта.

Сложные запросы

В BG биллинге, ввиду внутренней оптимизации, могут отсутствовать балансовые записи по договору за месяц, когда движения баланса не было. В этом случае считается, что раз движение 0, входящий остаток равен исходящему, он уже отражён в предыдущей записи. Да, с учётом накопления базы бывших (не действующих) абонентов, это даёт кое-какую экономию.

Но, чтобы строить SQL запросы по таким данным, неплохо бы их сначала привести в форму - одна балансовая запись за каждый месяц, вне зависимости от того менялся баланс или нет. Если делать это на лету, получается очень сложный запрос. Куда проще развернуть данные в виде таблицы.

Решение

С точки зрения отчета есть база, которая содержит:

  1. Таблица с версиями данных. Содержит № версии и дату загрузки.
  2. Представление атрибутов договоров. Ключ - ID договора.
  3. Представление балансов. Ссылается на ID договора и месяц.

Записи в таблицах под представлениями (2 и 3) ссылаются на записи таблицы версий (1), но сами представления показывают только последнюю версию.

Процесс наполнения базы выглядит так. Например, мы загружаем свежие данные 12.12.2011 в 12:05:

  1. В таблице с версиями данных (1) создается запись 16 с датой 12.12.2011 12:05.
  2. В таблицы соответствующих представлений (2 и 3) загружаются данные, где в поле номера версии записывается 16.

Отчеты делаются через представления.

Представим теперь, что отчет полученный в прошлом месяце и в этом месяце за один и тот же период отличается. Что бы ответить на вопрос "почему?", я могу сделать запрос уже к таблицам.

Преимущества

  1. Появляется некий способ ответа на вопрос "что изменилось?".
  2. Снижается нагрузка на рабочую БД сложными запросами.
  3. Многоэтажные подзапросы не повторяются из отчёта в отчёт, что сокращает объём отладки и упрощает изменения.
  4. Возможна замена исходной системы с сохранением всех старых отчётов, путём переписывания только механизма подготовки данных.

Недостатки

Когда я писал эту статью 8 декабря 2011 года, я ещё не прочитал нужных книг и не знал, что сделанная мною аналитическая база данных называется хранилищем данных (Data Warehouse).

У придуманного мною решения не было недостатков по сравнению с отсутствием какого-либо решения вообще. Но, сегодня, 25 февраля 2017 года, я опишу недостатки по сравнению с классическим Data Warehouse.

Расточительность

  1. Большинство договоров не изменялись между загрузками, но всё равно создавались новые записи для них.
  2. Ранее сформированные балансы сами по себе не должны были меняться, так как период в биллинге закрывался, хотя по необходимости это могло происходить. Но, в аналитической базе при каждой загрузке для каждого баланса за каждый месяц по каждому договору создавалить новые записи.

Именно это и послужило причиной смерти решения.

Одинаковая модель для всех атрибутов

Записи балансов за старый период были привязаны, тем не менее, к записям договоров в их последнем состоянии.

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

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

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

Кроме того, в классическом ХД, записи фактов (балансы), если они не менялись сами по себе, остаются привязанными к однажды выбранной записи измерения навсегда. Таким образом, если запись измерения дублируется (в связи с изменением некоторых атрибутов), старые факты могут группироваться и отбираться по старым значениям атрибутов (например, старые балансы по старым ответственным менеджерам).