Расчет баланса пользователя с несколькими таблицами затрат

Мы создаем предложение SaaS, в котором пользователь может нести расходы по различным типам транзакций, например:

  • Телефонные звонки
  • Отправка SMS-сообщений
  • Хранение аудиозаписей

Мы создали нашу систему для хранения стоимости каждой услуги, например таблица call_audit выглядит так:

Date       Call ID  Our Cost  User Cost Currency Duration User ID
---------- -------- --------- --------- -------- -------- -------
2018-01-02 sm_123   0.01      0.02      USD      72       us_1

Таблица sms_audit выглядит так:

Date       SMS ID   Our Cost  User Cost Currency User ID
---------- -------- --------- --------- -------- -------
2018-01-02 sm_123   0.01      0.02      USD      us_1

Затем есть таблица payment_audit с пользовательскими платежами и возвратами:

Date       User ID  Amount Currency Type 
---------- -------- ------ -------- ----
2018-01-02 us_1     12     USD      CHARGE
2018-01-02 us_1     -2     USD      REFUND

У нас также есть user таблица со столбцом balance, который мы уменьшаем, когда пользователь получает звонок, стоимость sms или возмещение. Мы увеличиваем его, когда пользователь платит на свой счет (CHARGE, как указано выше).

Но забегая вперед, я думаю, нам нужно что-то более устойчивое, чем одна цифра баланса, которая обновляется в коде.

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

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

Другой подход, о котором мы думали, заключался в том, чтобы иметь balance_transactions таблицу с debit, credit и текущим balance столбцом. Это, конечно, вызывает транзитивные зависимости между строками, что не очень хорошо, если вы ищете хорошо нормализованную БД. Это также означает, что мы дублируем данные, но является ли это приемлемым компромиссом в реальном мире?


person Leon Roy    schedule 09.06.2018    source источник
comment
Если бы я разрабатывал такую ​​систему, я бы сосредоточился на хранении каждой атомарной транзакции в виде отдельной строки в таблице без обновлений. Затем я выяснил, как получить нужную мне отчетность из этой таблицы - или, возможно, при необходимости, какие улучшения необходимо внести.   -  person Gordon Linoff    schedule 10.06.2018
comment
@GordonLinoff в точности наши мысли, поэтому мы называем эти таблицы таблицами call_audit и payment_audit. Строки таблицы читаются только после того, как все записи зафиксированы. Какой подход вы бы использовали для получения «отчетности» по таблицам аудита?   -  person Leon Roy    schedule 10.06.2018
comment
. . Запрос, объединяющий результаты, предположительно с использованием union all.   -  person Gordon Linoff    schedule 10.06.2018


Ответы (1)


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

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

person Tomasz Pala    schedule 09.06.2018
comment
Спасибо, интересный подход. Нам нужно будет обновлять данные после каждой оплаты / кредита, поскольку мы выставляем счет пользователю заранее, а не в конце месяца. Вы бы по-прежнему использовали материализованные представления, учитывая это? - person Leon Roy; 10.06.2018
comment
Нет, материализованные представления в таком случае, вероятно, были бы плохой идеей. Я бы пошел с триггером, обновляющим баланс (или частичным балансом), с некоторой процедурой проверки / оповещения, запускаемой один раз в неделю или около того. - person Tomasz Pala; 11.06.2018
comment
какие-либо достоинства чего-то вроде подхода к начальному / конечному балансу в дальнейшем, чтобы нам не приходилось анализировать все записи по мере роста списка транзакций пользователя? - person Leon Roy; 11.06.2018
comment
Возможно, стоит подумать, в зависимости от объема операций над учетной записью и самой структуры базы данных. Например, если таблицы транзакций секционируются ежемесячно, и только последний месяц хранится в более быстром хранилище, вам может потребоваться фиксировать ежемесячные балансы и повторно сканировать только текущий месяц. - person Tomasz Pala; 11.06.2018