source

데이터베이스 설계:계정 잔액 계산

factcode 2023. 4. 29. 09:55
반응형

데이터베이스 설계:계정 잔액 계산

계정 잔액을 계산하기 위해 데이터베이스를 어떻게 설계합니까?

현재 저는 거래 테이블에서 계좌 잔액을 계산합니다. 제 거래 테이블에는 "설명"과 "금액" 등이 있습니다.

그런 다음 모든 "금액" 값을 합산하여 사용자의 계정 잔액을 계산합니다.


제 친구에게 이것을 보여주었더니, 그는 제 데이터베이스가 증가할 때 속도가 느려지는 좋은 해결책이 아니라고 말했습니다.그는 계산된 계좌 잔액을 저장할 표를 따로 만들어야 한다고 말했습니다.이렇게 하면 두 개의 테이블을 유지해야 하는데, 이 테이블은 위험하기 때문에 계정 잔액 테이블이 동기화되지 않을 수 있습니다.

제안할 것이 있습니까?

편집: 옵션 2: 트랜잭션 테이블 "균형"에 열을 추가해야 합니다.이제 계산을 수행하기 위해 많은 데이터 행을 거칠 필요가 없습니다.

예를 들어, 존은 100달러의 신용카드를 구입하고, 60달러의 부채를 진 다음, 200달러의 신용카드를 추가합니다.

금액은 $100, 잔액은 $100입니다.

금액 - $60, 잔액 $40.

금액은 200달러, 잔액은 240달러입니다.

우아하게 해결된 적이 없는 오래된 문제.

제가 일했던 모든 은행 패키지는 계좌 주체와의 잔액을 저장합니다.이동 이력에서 바로 계산하는 것은 생각할 수 없습니다.

올바른 방법은 다음과 같습니다.

  • 이동 테이블에는 각 계정과 모든 계정에 대해 '개설 잔액' 트랜잭션이 있습니다.활성 이동 테이블에서 이전 이동을 기록 테이블로 이동해야 하는 경우 몇 년 후에 이 기능이 필요합니다.
  • 계정 엔티티에 잔액 필드가 있습니다.
  • 이동 테이블에는 신용 계정 및 차변 계정에 대한 계정 잔액을 업데이트하는 트리거가 있습니다.분명히, 그것은 책임감을 가지고 있습니다.트리거를 가질 수 없는 경우 커밋 제어로 움직임을 기록하는 고유 모듈이 필요합니다.
  • 오프라인에서 실행할 수 있는 '안전망' 프로그램이 있습니다. 이 프로그램은 모든 잔액을 다시 계산하고 잘못된 잔액을 표시하며 선택적으로 수정합니다.이것은 테스트에 매우 유용합니다.

일부 시스템은 모든 이동을 양수로 저장하고, 시작/종료 필드를 반전하거나 플래그를 사용하여 신용/직불을 표시합니다.개인적으로, 저는 대변 필드, 차변 필드 및 서명된 금액을 선호합니다. 이것은 역전을 훨씬 쉽게 해줍니다.

이러한 방법은 현금과 증권 모두에 적용됩니다.

증권 거래는 훨씬 까다로울 수 있습니다. 특히 기업 조치의 경우 하나 이상의 구매자 및 판매자 현금 잔액, 보안 포지션 잔액, 그리고 브로커/보관소를 업데이트하는 단일 거래를 수용해야 합니다.

당신은 경상수지를 저장하고 항상 최신 상태로 유지해야 합니다.트랜잭션 테이블은 과거에 발생한 일에 대한 기록일 뿐 현재 잔액을 가져오기 위해 높은 빈도로 사용되어서는 안 됩니다.많은 쿼리가 단순히 균형만 원하는 것이 아니라 필터링, 정렬 및 그룹화 등을 원한다는 점을 고려하십시오.복잡한 쿼리 중간에 생성한 모든 트랜잭션을 합산하는 성능 저하는 적당한 크기의 데이터베이스도 손상시킬 수 있습니다.

이 테이블 쌍에 대한 모든 업데이트는 트랜잭션에 있어야 하며 모든 것이 동기화된 상태로 유지되거나(계정이 한도를 초과하지 않음) 트랜잭션이 롤백되는지 확인해야 합니다.추가적인 조치로 이를 정기적으로 확인하는 감사 쿼리를 실행할 수 있습니다.

이것은 작업/트랜잭션 기록을 저장하기 위해 테이블 하나만 사용하여 얻은 데이터베이스 설계입니다.현재 많은 작은 프로젝트에서 매력적으로 일하고 있습니다.

이는 특정 설계를 대체하지 않습니다.이것은 대부분의 앱에 적합한 일반적인 솔루션입니다.

id:int 표준 행 ID

operation_type:int 작업 유형.급여, 징수, 이자 등

source_type: 작업이 진행되는 곳에서 int. 대상 테이블 또는 범주: 사용자, 은행, 공급자 등

source_id: 데이터베이스의 소스 ID

target_type: 작업이 적용되는 대상에 삽입. 대상 테이블 또는 범주: 사용자, 은행, 공급자 등

target_id:데이터베이스의 대상 ID

금액:19,2 서명된 가격의 양 또는 음의 합계 값

account_balance:19,2 서명된 결과 잔액

extra_value_a:signed(19,2 서명됨) [문자열 저장소를 사용하지 않고 가장 다용도로 사용할 수 있는 옵션] 이자율, 할인, 할인 등의 추가 숫자를 저장할 수 있습니다.

작성된_장소:삭제

source_type 및 target_type의 경우 appart에서 열거형 테이블을 사용하는 것이 좋습니다.

특정 균형을 원한다면 created_at descending limit를 1로 정렬한 마지막 작업을 쿼리하면 됩니다.source, target, operation_type 등을 기준으로 조회할 수 있습니다.

성능을 향상시키려면 현재 잔액을 필요한 대상 개체에 저장하는 것이 좋습니다.

물론 현재 잔액을 각 행에 저장해야 합니다. 그렇지 않으면 너무 느립니다.개발을 단순화하기 위해 제약 조건을 사용하여 데이터 무결성을 트리거 및 주기적으로 확인할 필요가 없습니다.비즈니스 규칙을 적용하기 위한 정규화 해제에 대해 설명했습니다. 실행 총계

이 문제에 대한 일반적인 해결책은 스냅샷 스키마에서 월별 오프닝 밸런스를 유지하는 것입니다.당좌대월 잔액 계산은 당월 거래 데이터를 당월 오프닝 잔액에 추가하여 수행할 수 있습니다.이 접근 방식은 특히 통화 전환 및 재평가가 있을 수 있는 계정 패키지에서 종종 사용됩니다.

데이터 볼륨에 문제가 있는 경우 오래된 잔액을 보관할 수 있습니다.

또한 시스템에 전용 외부 데이터 웨어하우스나 관리 보고 기능이 없는 경우 잔액을 보고하는 데 유용할 수 있습니다.

당신의 친구는 틀렸고 당신은 옳습니다, 그리고 저는 당신이 지금 상황을 바꾸지 않는 것을 조언하고 싶습니다.
이로 인해 DB가 느리게 진행되고 나머지(적절한 인덱싱)를 모두 확인한 후 일부 정규화를 사용할 수 있습니다.
그런 다음 Accounts 테이블에 BalanceAt StartOf Year 필드를 넣고 올해 기록(또는 이와 유사한 접근 방식)만 요약할 수 있습니다.
하지만 저는 이 접근법을 미리 권장하지는 않을 것입니다.

매우 간단한 방법으로 오프닝 밸런스를 저장할 수 있는 방법을 제안합니다.

  1. 트랜잭션 테이블에 업데이트 또는 삽입 후에만 호출할 트리거 함수를 만듭니다.

  2. 계정의 마스터 테이블에 이름을 가진 열을 작성합니다. 이름은 오프닝 밸런스입니다.

  3. 마스터 테이블의 오프닝 밸런스 열에 오프닝 밸런스를 배열에 저장합니다.

  4. 서버 사이드 언어를 사용할 필요도 없습니다. 이 저장소 배열을 사용하면 Postgre에서 사용할 수 있는 것과 같은 데이터베이스 배열 기능을 사용할 수 있습니다.SQL.

  5. 배열에서 잔액을 다시 계산하려면 트랜잭션 테이블을 배열 함수로 그룹화하고 마스터 테이블의 전체 데이터를 업데이트하십시오.

나는 포스트그레에서 이것을 했습니다.SQL은 정상적으로 작동합니다.

트랜잭션 테이블이 무거워지는 기간 동안 날짜를 기준으로 트랜잭션 테이블의 파티션을 분할하여 성능을 향상시킬 수 있습니다.이 접근 방식은 매우 쉬우며 조인 테이블의 테이블 수가 적으면 높은 성능을 얻을 수 있기 때문에 테이블을 조인할 때 성능이 저하될 수 있는 추가 테이블을 사용할 필요가 없습니다.

제 접근 방식은 차변 열에 차변을 저장하고, 신용 열에 대변을 저장하며, 데이터를 가져올 때 차변과 신용 배열의 두 배열을 생성하는 것입니다.그런 다음 선택한 데이터를 어레이에 계속 추가하고 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)

간단한 대답: 세 가지를 모두 수행합니다.

현재 잔액을 저장하고 각 트랜잭션에서 해당 시점의 현재 잔액에 대한 이동 및 스냅샷을 저장합니다.이는 감사에서 조정할 수 있는 추가적인 무언가를 제공할 것입니다.

저는 핵심 은행 시스템에 대해 일해본 적은 없지만, 투자 관리 시스템에 대해서는 일해본 적이 있습니다. 제 경험으로는 이렇게 되어 있습니다.

언급URL : https://stackoverflow.com/questions/4373968/database-design-calculating-the-account-balance

반응형