Проектирование базы данных: расчет баланса счета


Как создать базу данных для расчета баланса счета?

1) в настоящее время я вычисляю баланс счета из таблицы транзакций В моей таблице транзакций у меня есть "описание" и "сумма" и т. д..

затем я бы сложил все значения "суммы", и это будет работать с балансом учетной записи пользователя.


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

какие будут предложения?

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

пример Джон покупает $ 100 кредит, он долг $ 60, затем он добавляет $ 200 кредит.

Сумма $ 100, Баланс $100.

Сумма - $ 60, Баланс $ 40.

Сумма $ 200, Баланс $ 240.

9 52

9 ответов:

старая проблема, которая никогда не была изящно решена.

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

правильно:

  • таблица движения имеет ' отверстие транзакция баланса для каждого счета. Вам понадобится это в течение нескольких лет, когда вы нужно переместить старые движения из активная таблица движения к а история стол.
  • объект счета имеет баланс поле
  • есть триггер на движение таблица, которая обновляет учетную запись остатки по дебетованным и зачисленным счетам. Очевидно, что у него есть обязательства управление. Если у вас нет триггера, то должен быть уникальный модуль, который записывает движения под контроля обязательств
  • у вас есть программа "сеть безопасности" вы может работать в автономном режиме, который повторно вычисляет все балансы и дисплеи (и при необходимости корректирует) ошибочное балансы. Это очень полезно для тестирование.

некоторые системы хранят все движения в виде положительных чисел и выражают кредит/дебет, инвертируя поля from/to или с флагом. Лично я предпочитаю кредитное поле, дебетовое поле и подписанную сумму, это значительно упрощает отслеживание разворотов.

обратите внимание, что эти методы применяются как к денежным средствам, так и к ценным бумагам.

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

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

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

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

Если у вас есть проблемы с объемом данных, вы можете архивировать старые балансы.

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

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

ваш друг правы, и вы правы, и я бы советовал не менять.
Если ваша БД когда-либо замедляется из-за этого, и после того, как вы проверили все остальное (правильная индексация), может быть полезна некоторая денормализация.
Затем вы можете поместить поле BalanceAtStartOfYear в таблицу Accounts и суммировать только записи этого года (или любой подобный подход).
Но я бы, конечно, не рекомендовал этот подход заранее.

вот хотел бы предложить вам, как вы можете сохранить свой начальный баланс с очень простым способом: -

  1. создайте функцию триггера в таблице транзакций, которая будет вызываться только после обновления или вставки.

  2. создайте столбец с именем в главной таблице именования счета начального баланса.

  3. сохраните начальный баланс в массиве в столбце начальный баланс в master стол.

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

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

Я сделал это в PostgreSQL и работает нормально.

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

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

Это не заменяет конкретную конструкцию. Это универсальное решение, которое может соответствовать большинству приложений.

id: int стандартный идентификатор строки

operation_type: int тип операции. платить, собирать, интерес и т. д.

source_type: int от места, где операция продолжается. целевая таблица или категория: пользователь, банк, поставщик и т. д.

source_id: int идентификатор источника в базе данных

target_type: int к чему применяется операция. целевая таблица или категория: пользователь, банк, поставщик и т. д.

target_id: int идентификатор цели в базе данных

в сумме: десятичное число (19,2 подписано) значение цены положительное или отрицательно к суммированному

account_balance: десятичное число (19,2 подписано) результирующий баланс

extra_value_a:decimal (19,2 знак) [это был самый универсальный вариант без использования строкового хранилища] вы можете сохранить дополнительный номер: процентный процент, скидку, скидку и т. д.

created_at:метка

для source_type и target_type было бы лучше использовать перечисление или таблицы аппарт.

Если вам нужен определенный баланс, вы можете просто запросить последнюю операцию, отсортированную по created_at по убыванию до 1. Вы можете запросить по источнику, цели, operation_type и т. д.

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

мой подход заключается в том, чтобы хранить дебеты в столбце дебет, кредит в столбце кредит и при извлечении данных создать два массива, дебет и кредитный массив. Затем продолжайте добавлять выбранные данные в массив и сделайте это для python:

def real_insert(arr, index, value):
    try:
        arr[index] = value
    except IndexError:
        arr.insert(index, value)


def add_array(args=[], index=0):
    total = 0
    if index:
        for a in args[: index]:
            total += a
    else:
        for a in args:
            total += a
    return total

затем

for n in range(0, len(array), 1):
    self.store.clear()
    self.store.append([str(array[n][4])])
    real_insert(self.row_id, n, array[n][0])
    real_insert(self.debit_array, n, array[n][7])
    real_insert(self.credit_array, n, array[n][8])
    if self.category in ["Assets", "Expenses"]:
        balance = add_array(self.debit_array) - add_array(self.credit_array)
    else:
        balance = add_array(self.credit_array) - add_array(self.debit_array)

простой ответ: сделайте все три.

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

Я никогда не работал над основными банковскими системами, но я работал над системами управления инвестициями, и по моему опыту это делается именно так.