Проектирование базы данных: расчет баланса счета
Как создать базу данных для расчета баланса счета?
1) в настоящее время я вычисляю баланс счета из таблицы транзакций В моей таблице транзакций у меня есть "описание" и "сумма" и т. д..
затем я бы сложил все значения "суммы", и это будет работать с балансом учетной записи пользователя.
Я показал это своему другу, и он сказал, что это не очень хорошее решение, когда моя база данных растет, она будет замедляться???? Он сказал, что я должен создать отдельную таблицу для хранения расчетного счета. Если бы это было сделано, мне придется поддерживать две таблицы, и это рискованно, таблица баланса счета может выйти из синхронизации.
какие будут предложения?
EDIT: вариант 2: я должен добавить дополнительный столбец в мои таблицы транзакций "баланс". теперь мне не нужно проходить через много строк данных, чтобы выполнить мой расчет.
пример Джон покупает $ 100 кредит, он долг $ 60, затем он добавляет $ 200 кредит.
Сумма $ 100, Баланс $100.
Сумма - $ 60, Баланс $ 40.
Сумма $ 200, Баланс $ 240.
9 ответов:
старая проблема, которая никогда не была изящно решена.
все банковские пакеты, с которыми я работал, хранят баланс с учетной записью. Вычислить его на лету из истории движения немыслимо.
правильно:
- таблица движения имеет ' отверстие транзакция баланса для каждого счета. Вам понадобится это в течение нескольких лет, когда вы нужно переместить старые движения из активная таблица движения к а история стол.
- объект счета имеет баланс поле
- есть триггер на движение таблица, которая обновляет учетную запись остатки по дебетованным и зачисленным счетам. Очевидно, что у него есть обязательства управление. Если у вас нет триггера, то должен быть уникальный модуль, который записывает движения под контроля обязательств
- у вас есть программа "сеть безопасности" вы может работать в автономном режиме, который повторно вычисляет все балансы и дисплеи (и при необходимости корректирует) ошибочное балансы. Это очень полезно для тестирование.
некоторые системы хранят все движения в виде положительных чисел и выражают кредит/дебет, инвертируя поля from/to или с флагом. Лично я предпочитаю кредитное поле, дебетовое поле и подписанную сумму, это значительно упрощает отслеживание разворотов.
обратите внимание, что эти методы применяются как к денежным средствам, так и к ценным бумагам.
операции с ценными бумагами могут быть намного сложнее, специально для корпоративных действий вам нужно будет разместить одну транзакцию, которая обновляет один или несколько остатков денежных средств покупателя и продавца, их балансы позиций безопасности и, возможно, брокера/депозитария.
вы должны хранить баланс текущего счета и поддерживать его в актуальном состоянии в любое время. Таблица транзакций-это просто запись того, что произошло в прошлом, и не должна использоваться с высокой частотой только для извлечения текущего баланса. Учтите, что многие запросы не просто хотят балансы, они хотят фильтровать, сортировать и группировать по ним и т. д. Штраф за производительность суммирования каждой транзакции, которую вы когда-либо создавали в середине сложных запросов, будет калечить даже базу данных скромных размер.
все обновления этой пары таблиц должны быть в транзакции и должны гарантировать, что либо все остается в синхронизации (и счет никогда не перерасходует свой предел), либо транзакция откатывается. В качестве дополнительной меры вы можете запускать запросы аудита, которые периодически проверяют это.
общим решением этой проблемы является поддержание (скажем) ежемесячного начального баланса в схеме моментального снимка. Расчет текущего баланса может быть выполнен путем добавления транзакционных данных за месяц в ежемесячный начальный баланс. Этот подход часто используется в пакетах счетов, особенно в тех случаях, когда у вас может быть конвертация и переоценка валюты.
Если у вас есть проблемы с объемом данных, вы можете архивировать старые балансы.
также, балансы могут быть полезно для создания отчетов, если в системе нет выделенного внешнего хранилища данных или объекта управленческой отчетности.
конечно нужно сохранить ваш текущий баланс с каждой строкой, в противном случае это слишком медленно. Для упрощения разработки можно использовать ограничения, чтобы не требовались триггеры и периодические проверки целостности данных. Я описал его здесь денормализация для применения бизнес-правил: промежуточные итоги
ваш друг правы, и вы правы, и я бы советовал не менять.
Если ваша БД когда-либо замедляется из-за этого, и после того, как вы проверили все остальное (правильная индексация), может быть полезна некоторая денормализация.
Затем вы можете поместить поле BalanceAtStartOfYear в таблицу Accounts и суммировать только записи этого года (или любой подобный подход).
Но я бы, конечно, не рекомендовал этот подход заранее.
вот хотел бы предложить вам, как вы можете сохранить свой начальный баланс с очень простым способом: -
создайте функцию триггера в таблице транзакций, которая будет вызываться только после обновления или вставки.
создайте столбец с именем в главной таблице именования счета начального баланса.
сохраните начальный баланс в массиве в столбце начальный баланс в master стол.
вам даже не нужно использовать язык на стороне сервера используйте этот массив хранилища просто вы можете использовать функции массива базы данных, такие как доступные в PostgreSQL.
Если вы хотите пересчитать баланс Открытия в массиве, просто сгруппируйте таблицу транзакций с функцией массива и обновите все данные в главной таблице.
Я сделал это в 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)
простой ответ: сделайте все три.
хранить текущий баланс; и в каждой транзакции хранить движение и снимок текущего баланса в этот момент времени. Это даст что-то дополнительно для согласования в какой-либо ревизии.
Я никогда не работал над основными банковскими системами, но я работал над системами управления инвестициями, и по моему опыту это делается именно так.