58

つまり、通常の銀行口座と同じように、多くの取引があり、お金の流入または流出が発生します。口座残高は、取引額を合計するだけでいつでも導き出すことができます。この場合、更新された口座残高をデータベースに保存するか、必要に応じて再計算するか、どちらが良いでしょうか?

アカウントあたりの予想取引量: <1 日 5

アカウント残高の予想される取得: トランザクションが発生するたびに、それ以外の場合は平均して 1 日に 1 回。

これについてどのように決定を下すことをお勧めしますか? どうもありがとう!

4

2 に答える 2

171

序文

客観的な真実があります: 監査要件です。また、公的資金を扱う際には、遵守しなければならない立法府があります。

すべてのアカウンティング要件を実装する必要はありません。必要な部分だけを実装できます。

逆に、標準的なアカウンティング要件 (その一部)以外のものを実装することはお勧めできません。これにより、バグの数や負荷がしきい値を超えたり、システムが拡張したりしたときに、再実装する必要があることが保証されるためです。 . 回避できるコストであり、回避する必要があります。

また、次のことも明記する必要があります。資格も認定もされていない「監査人」を雇わないでください。資格のない開発者を雇った場合と同じ結果が生じます。税務署があなたに罰金を科せば、さらに悪いことになるかもしれません。

方法

それほど原始的ではない国の標準的な会計方法はこれです。あなたがそうするなら、他の「ベストプラクティス」。

この方法は、同様の操作を行うすべてのシステムに適用されます。ニーズ; 過去の月次数値と在庫管理などの当月の要件との比較。

考慮

まず、考慮事項。

  1. データを複製しないでください。
    現在の残高を導き出すことができる場合 (ここでは簡単です)、集計列でそれを複製しないでください。このような列はデータの重複です。正規化ルールに違反します。さらに、他の方法では存在しない更新異常を作成します。

  2. サマリー列を使用する場合、トランザクションが更新されるたびに (新しいトランザクションが挿入されたときではなく、変更されたとき)、サマリー列のは古くなるため、とにかく常に更新する必要があります。それが更新異常の結果です。それはそれを持つ価値を排除します。

  3. 外部公開。
    ポイントを分ける。毎月の銀行取引明細書のように残高が公開される場合、そのような文書には通常、法的制限と意味が含まれるため、公開された現在の残高の値は公開後に変更されてはなりません。

    • 外部に公開された図の公開日以降のデータベース内の変更は、不正行為、詐欺などの証拠です。

      • 出版された歴史を変えようとするそのような行為は、初心者の特徴です。初心者や精神病患者は、歴史は変えられると主張するでしょう。しかし、誰もが知っているように、法律の無知は正当な弁護にはなりません。
    • 2015 年 4 月に、銀行が 2014 年 12 月の銀行取引明細書で発行した現在の残高を変更することを望まないでしょう。

    • その数値は、公開された変更不可能な監査数値として表示する必要があります。

  4. 過去に発生したエラーを修正し、現在修正中のエラーを修正するために、必要な修正または調整は、現在の月に新しいトランザクションとして行われます (前の月または期間に適用される場合でも)。

    これは、該当する月が閉じているためです。監査済み。なぜなら、それが起こって記録された後は、歴史を変えることはできないからです。有効な月は現在の月のみです。

    • あまり原始的ではない国での利付システムなどで、誤りが発見され、それが歴史的な影響を及ぼした場合 (たとえば、2015 年 4 月に証券の計算された利子が正しくないことがわかりました。 2014) では、修正された利払/控除の値が、エラーが発生した日数に対して今日計算され、その合計が当月のトランザクションとして挿入されます。繰り返しになりますが、有効な月は現在の月のみです。

      そしてもちろん、証券の利率も同様に修正して、その誤りが繰り返されないようにする必要があります。

    • 銀行による貯蓄 (利子付き) 口座の利息の計算に誤りがあり、それを修正した場合、当月の調整値全体を構成する 1 つの預金が得られます。それは当月のトランザクションです。

      銀行は次のことを行いません。履歴を変更します。過去の月ごとに利息を適用します。過去の銀行取引明細書を思い出してください。過去の銀行取引明細書を再発行します。いいえ。多分第三世界の国を除いて。

    • 同じ原則が在庫管理システムにも当てはまります。それは正気を維持します。

  5. すべての実際の会計システム (つまり、豊富なミッキー マウスの「パッケージ」とは対照的に、該当する国の監査機関によって認定されているシステム) は、トランザクションに複式入力システムを使用しています。最も重要なのは、資金が「失われる」ことがないことです。それには総勘定元帳と複式簿記が必要です。

    • あなたはそれを求めていませんし、必要もないので、ここでは説明しません。しかし、お金が「なくなった」場合に備えて、覚えておいてください。これは、一時的な解決策ではなく、実装する必要があるためです。まだ別の認定されていない「パッケージ」ではありません。

    この回答は、尋ねられた質問にサービスを提供しますが、これは複式簿記ではありません。
    その主題の完全な取り扱い (詳細なデータ モデル、会計トランザクションの例、影響を受ける行、および SQL コードの例) については、この Q&A:
    複式簿記のリレーショナル データ モデル を参照してください。

  6. パフォーマンスに影響を与える主要な問題は、この質問の範囲外です。それらは、本物のリレーショナル データベースを実装するかどうかの領域にあります (たとえば、1960 年代のレコード ファイリング システムはRecord IDs、SQL データベース コンテナに展開され、快適)。

    • 本物のリレーショナル キーなどを使用すると、テーブルの数に関係なく、高いパフォーマンスが維持されます。

    • 逆に言えば、RFS のパフォーマンスは悪く、単純に実行できません。RFS のコンテキストで使用される場合、「スケール」は不正な用語です。原因を隠し、原因以外のすべてに対処しようとします。最も重要なことは、そのようなシステムにはリレーショナル整合性がまったくないことです。関係力; またはリレーショナル システムのリレーショナル スピード。

実装

リレーショナル データ モデル • 口座残高

アカウント

リレーショナル データ モデル • インベントリ

請求書

表記

  • 私のデータ モデルはすべて、1993 年以来のリレーショナル データベースのモデリングの標準であるIDEF1Xでレンダリングされています。

  • My IDEF1X Introductionは、リレーショナル モデルやそのモデリング手法に慣れていない人にとって必読です。IDEF1X モデルは細部と精度が豊富で、必要なすべての詳細を示していますが、自家製のモデルはそれよりはるかに少ないことに注意してください。つまり、表記法を理解する必要があります。

コンテンツ

  1. アカウントごとに、明細書の日付 (通常は月の最初の日) およびその他の明細書の詳細と共に ClosingBalanceAccountStatement表 (1 か月あたり 1 行) に があります。AccountNo

    • これは、監査と健全性の目的で要求されるため、複製ではありません。

      在庫の場合はQtyOnHandPartAuditテーブルの列です ( PartCode1 か月あたり 1 行) 。

    • 照会する必要があるトランザクション行の範囲を当月に制限するという点で、追加の値があります。

      • 繰り返しますが、テーブルがリレーショナルの場合、プライマリ キーはAccountTransaction( AccountNo, Transaction DateTime) になり、ミリ秒の速度でトランザクションを取得します。

      • 一方、レコード ファイリング システムの場合、「主キー」は でありTransactionID、トランザクション日によって現在の月を取得します。これは、正しくインデックス付けされている場合とされていない場合があり、必要な行がファイル全体に分散されます。いずれにせよ、ClusteredIndex の速度よりもはるかに遅く、スプレッドが原因で、テーブルスキャンが発生します。

  2. テーブルはシンプルなままです(AccountTransaction銀行口座トランザクションの実際の概念はシンプルです)。それは単一の肯定的なAmountコラムを持っています。

  3. 各 についてAccountCurrentBalanceは次のとおりです。

    • AccountStatement.ClosingBalance前月の日付、便宜上翌月の最初の日付

      (在庫の為、PartAudit.QtyOnHand

    • プラスAccountTransaction.Amounts当月のの合計。TransactionTypeは入金を示します。

      (在庫の為、PartMovement.Quantity

    • AccountTransaction.Amounts当月のの SUM を引いたもので、`MovementType は引き出しを示します。

  4. このメソッドでは、AccountTransactions当月のみが流動的な状態にあるため、導出する必要があります。過去の月はすべて公開され、クローズされているため、Audit の数値を使用する必要があります

  5. テーブル内の古い行はAccountTransaction削除できます。公金は10年以上、それ以外は5年、趣味クラブ制度は1年。

  6. もちろん、会計システムに関連するすべてのコードで、正規の OLTP 標準と正規の SQL ACID トランザクションを使用することが不可欠です。

  7. この設計には、スコープレベルのパフォーマンスに関するすべての考慮事項が組み込まれています (これが明らかでない場合は、拡張を依頼してください)。データベース内のスケーリングは問題ではありません。残っているスケーリングの問題は、正直なところデータベースの外にあります。


是正アドバイス

これらの項目を記載する必要があるのは、多くの SO Answers で誤ったアドバイスが提供されており (もちろん、大衆によって民主的に賛成票が投じられているためです)、インターネットには誤ったアドバイスがぎっしり詰まっています (アマチュアは自分の主観的な意見を公開するのが大好きです)。真実」):

  1. 明らかに、明確なデータモデルに対して操作するために、技術用語でメソッドを指定したことを理解していない人もいます。そのため、特定の国における特定のアプリケーションの疑似コードではありません。メソッドは有能な開発者向けであり、手で導く必要がある人には十分に詳細ではありません。

    • また、月の締め切り期間が例であることも理解していません。税務署の目的での締め切りが四半期ごとである場合は、必ず四半期ごとの締め切りを使用してください。法的要件が年次のみの場合は、年次を使用します。

    • 外部またはコンプライアンスの目的でカットオフが四半期ごとである場合でも、会社は内部監査と健全性の目的で月次のカットオフを選択する可能性があります (つまり、流動的な状態の期間の長さを最小限に抑えるため)。 .

      例えば。オーストラリアでは、企業の税務署の締め切りは四半期ごとですが、大企業は毎月在庫管理を締め切ります (これにより、長期間にわたってエラーを追跡する必要がなくなります)。

      例えば。銀行には毎月法令順守要件があるため、数値について内部監査を行い、毎月帳簿を締めます。

    • 原始国やならず者国家では、銀行は明らかに悪意のある目的のために、流動状態の期間を最大に保ちます。それらのいくつかは、コンプライアンスレポートを毎年作成するだけです。これが、オーストラリアの銀行が破綻しない理由の 1 つです。

  2. AccountTransaction表では、金額の列にマイナス/プラスを使用しないでください。お金は常に正の値を持ち、負の 20 ドル (または、あなたが私に負っているマイナス 50 ドル) などというものはありません。

  3. 動きの方向、または資金を使って何をしようとしているのかは、別個の個別の事実です (へAccountTransaction.Amount)。これには別の列が必要です (1 つのデータに 2 つの事実があると、正規化ルールが破られ、その結果、コードが複雑になります)。

    • 開始点として、入出TransactionType金の ( ) を主キーとする参照テーブルを実装します。システムが成長するにつれて、調整クレジットD, Wに ( ) を追加するだけです。A, a, F, w調整借方; 銀行の手数料; ATM_引き出し; 等

    • コードの変更は必要ありません。

  4. 一部の原始的な国では、訴訟要件により、トランザクションを一覧表示するレポートでは、すべての行に現在の合計を表示する必要があると規定されています。(注意してください、これは監査の要件ではありません。[(上記の方法を参照) 裁判所の要件よりも優れているためです。監査人は弁護士よりもやや愚かではないなどです。)

    明らかに、私は裁判所の要求に異議を唱えません。問題は、プリミティブ コーダーがそれを次のように変換すること AccountTransaction.CurrentBalance です。彼らは次のことを理解していません。

    • レポートに列を印刷するという要件は、データベースに値を保存することを指示するものではありません

    • あらゆる種類の現在の合計は派生値であり、簡単にコーディングできます (簡単でない場合は質問を投稿してください)。レポートに必要なコードを実装するだけです。

    • 現在の合計を実装します。AccountTransaction.CurrentBalance列として恐ろしい問題が発生します。

      • 派生可能であるため、複製された列が導入されます。正規化を破る。更新異常を導入します。

      • 更新の異常: トランザクションが歴史的に挿入されるか、AccountTransaction.Amount変更されるたびに、AccountTransaction.CurrentBalances その日付から現在までのすべてを再計算して更新する必要があります。

    • 上記の場合、法廷で使用するために提出された報告書は現在では廃止されています (オンライン データのすべての報告書は、印刷された時点で廃止されます)。すなわち。印刷; レビュー; トランザクションを変更します。再印刷; あなたが満足するまで、再レビューしてください。いずれにしても無意味です。

    • そのため、原始的ではない国では、裁判所は古い印刷された論文を受け入れず、出版された数字のみを受け入れます。すでに監査要件の対象となっており (上記の方法を参照)、取り消したり、変更したり、再印刷したりすることができない銀行取引明細書。


コメント

アレックス:
はい、コードは見やすいと思います。ありがとうございます。サンプルの「バケツショップ」でさえ、最初のスキーマを一度だけ永久に見ることができ、世界をより良くするでしょう.

上記のデータ モデルの場合。

コード • レポートの現在の残高

SELECT  AccountNo,
        ClosingDate = DATEADD( DD, -1 Date ), -- show last day of previous
        ClosingBalance,
        CurrentBalance = ClosingBalance + (
            SELECT SUM( Amount )
                FROM AccountTransaction
                WHERE AccountNo = @AccountNo
                    AND TransactionTypeCode IN ( "A", "D" )
                    AND DateTime >= CONVERT( CHAR(6), GETDATE(), 2 ) + "01"
                ) - (
            SELECT SUM( Amount )
                FROM AccountTransaction
                WHERE AccountNo = @AccountNo
                    AND TransactionTypeCode NOT IN ( "A", "D" )
                    AND DateTime >= CONVERT( CHAR(6), GETDATE(), 2 ) + "01"
                )
    FROM AccountStatement
    WHERE AccountNo = @AccountNo
        AND Date = CONVERT( CHAR(6), GETDATE(), 2 ) + "01"

そのトランザクション ログを非正規化することで、より便利なクエリと、より多くの tx タイプを追加したときにビュー/具体化されたビューの変更が少ない通常の形式を交換します

神よ私を救い給え。

  1. 標準に逆らうと、壊れてはならない、先進国では決して壊れないものが壊れる、第三世界の立場に身を置くことになります。

    当局に正しい答えを求めて、それに対して反論したり、標準以下の方法を主張したりするのは、おそらく良い考えではありません。

  2. 非正規化 (ここ) は、TransactionTypeCode から派生できる重複列である Update Anomaly を引き起こします。コーディングを簡単にしたいが、1 か所ではなく 2 か所でコーディングしたい。これは、まさにエラーが発生しやすい種類のコードです。

    EF Codd 博士のリレーショナル モデルに従って完全に正規化されたデータベースは、最も簡単で、最も論理的で、単純なコードを提供します。(私の仕事では、すべてのレポートが 1 つの で処理できることを契約で保証していますSELECT。)

  3. ENUMは SQL ではありません。(フリーウェアの NONsql スイートは SQL に準拠していませんが、SQL では不要な追加機能があります。) アプリが商用 SQL プラットフォームに移行する場合は、それらすべてENUMsを通常のルックアップ テーブルとして書き直す必要があります。aCHAR(1)または aINTを PK として使用します。そうすれば、それが実際には PK を持つテーブルであることに気付くでしょう。

  4. エラーの値はゼロです (マイナスの結果もあります)。真実の値は 1 です。私は 1 を 0 と交換しません。したがって、これはトレードオフではありません。それはあなたの開発上の決定です。

于 2015-04-18T05:18:02.617 に答える
1

これはかなり主観的です。私が考慮に入れることをお勧めする事項は次のとおりです。

  1. 現在、いくつのアカウントがありますか?
  2. 将来、いくつのアカウントを持つ予定ですか?
  3. スケーラビリティにどの程度の価値を置いていますか?
  4. データベースとコードを更新して、残高を独自のフィールドとして追跡するのはどのくらい難しいですか?
  5. 対処しなければならない差し迫った開発上の問題はありますか?

提案された 2 つのアプローチのメリットに関しては、オンデマンドでトランザクションの値を合計する方が、実装が簡単で迅速なアプローチになる可能性があります。

ただし、現在の口座残高をデータベースのフィールドとして維持し、それを更新するほどにはスケーリングしません。また、トランザクションを続行する前に、各トランザクションで現在の口座残高を計算するクエリを実行する必要があるため、トランザクション全体の処理時間が多少長くなります。実際には、非常に多数のアカウント/トランザクションを持っているか、非常に近い将来に発生することが予想される場合を除き、これらは小さな問題である可能性があります.

2 番目のアプローチの欠点は、最初のセットアップにおそらくより多くの開発時間/労力がかかることです。また、アカウント内のトランザクションを同期して、それぞれが正確に残高を確認して更新できるようにする方法を検討する必要がある場合があります。常に。

したがって、ほとんどの場合、プロジェクトのニーズが何であるか、現時点で開発時間をどこに費やすのが最適か、パフォーマンスとスケーラビリティが現実のものになったときに、後で 2 番目のアプローチを実装するのではなく、今ソリューションを将来保証する価値があるかどうかにかかっています。理論よりも、問題。

于 2015-04-17T02:16:46.743 に答える