web-dev-qa-db-fra.com

Solde de compte dérivé vs solde de compte stocké pour un simple compte bancaire?

Donc, c'est comme nos comptes bancaires normaux où nous avons beaucoup de transactions qui entraînent des entrées ou des sorties d'argent. Le solde du compte peut toujours être dérivé en additionnant simplement les valeurs de transaction. Quoi de mieux dans ce cas, stocker le solde du compte mis à jour dans la base de données ou le recalculer chaque fois que nécessaire?

Volume de transactions prévu par compte: <5 par jour

Récupération attendue du solde du compte: chaque fois qu'une transaction se produit et une fois par jour en moyenne sinon.

Comment proposeriez-vous de prendre une décision à ce sujet? Merci beaucoup!

34
Anmol Gupta

Préface

Il y a une vérité objective: les exigences d'audit. De plus, lorsqu'il s'agit de fonds publics, il y a une législature qui doit être respectée.

Vous n'avez pas à implémenter l'exigence comptable complète, vous pouvez implémenter uniquement les pièces dont vous avez besoin.

Inversement, il serait mal avisé d'implémenter quelque chose autre que l'exigence comptable standard (les parties de celle-ci) car cela garantit que lorsque le nombre de bugs ou la charge dépasse un certain seuil, ou le système se développe, vous devrez réimplémenter. Un coût qui peut et doit donc être évité.

Il faut aussi préciser: n'engagez pas un "auditeur" non qualifié et non accrédité. Il y aura des conséquences, comme si vous aviez embauché un développeur non qualifié. Cela pourrait être pire si l'administration fiscale vous inflige une amende.

Méthode

La méthode de comptabilité standard dans les pays pas si primitifs est la suivante. La "meilleure pratique", si vous voulez, chez les autres.

Cette méthode s'applique à tout système ayant des opérations similaires; Besoins; les chiffres mensuels historiques par rapport aux exigences du mois en cours, tels que le contrôle des stocks, etc.

Considération

Tout d'abord, les considérations.

  1. Ne dupliquez jamais de données.
    Si le solde actuel peut être dérivé (et ici c'est simple), ne le dupliquez pas avec une colonne récapitulative. Une telle colonne est une duplication de données. Il enfreint les règles de normalisation. De plus, il crée une anomalie de mise à jour, qui autrement n'existe pas.

  2. Si vous utilisez une colonne récapitulative, chaque fois que les transactions sont mises à jour (comme modifiées, pas comme lorsqu'une nouvelle transaction est insérée), la colonne récapitulative valeur devient obsolète, elle doit donc être mise à jour tout le temps de toute façon. C'est la conséquence de l'anomalie de mise à jour. Ce qui élimine la valeur de l'avoir.

  3. Publication externe.
    Point séparé. Si le solde est publié, comme dans un relevé bancaire mensuel, ces documents ont généralement des restrictions et des implications légales, de sorte que la valeur du solde actuel publié ne doit pas changer après la publication.

    • Tout changement, après la date de publication, dans la base de données, d'un chiffre publié en externe, constitue une preuve de conduite malhonnête, de fraude, etc.

      • Un tel acte, tentant de changer l'histoire publiée, est la marque d'un novice. Les novices et les malades mentaux insisteront pour que l'histoire puisse être modifiée. Mais comme chacun doit le savoir, l'ignorance de la loi ne constitue pas un moyen de défense valable.
    • Vous ne voudriez pas que votre banque, en avril 2015, modifie votre solde actuel qu'elle vous a publié dans son relevé bancaire de décembre 2014.

    • Ce chiffre doit être considéré comme un chiffre d'audit, publié et immuable.

  4. Pour corriger une erreur qui a été commise dans le passé, qui est en train d'être corrigée dans le présent, la correction ou l'ajustement qui est nécessaire est effectué en tant que nouvelle transaction dans le mois en cours (même s'il s'applique à un mois ou à une durée antérieurs).

    En effet, ce mois applicable est fermé; Vérifié; et publié, car on ne peut pas changer l’histoire une fois qu’elle est arrivée et qu’elle a été enregistrée. Le seul mois effectif est le mois en cours.

    • Pour les systèmes portant intérêt, etc., dans les pays moins primitifs, lorsqu'une erreur est détectée et qu'elle a un effet historique (par exemple, vous découvrez en avril 2015 que les intérêts calculés sur un titre sont incorrects depuis décembre 2014), la valeur du paiement/de la déduction des intérêts corrigés est calculée aujourd'hui, pour le nombre de jours qui étaient erronés, et la somme est insérée en tant que transaction dans le mois en cours. Encore une fois, le seul mois effectif est le mois actuel.

      Et bien sûr, le taux d'intérêt du titre doit également être corrigé, afin que cette erreur ne se répète pas.

    • Si vous constatez une erreur dans le calcul par votre banque des intérêts sur votre compte d'épargne (portant intérêt) et que vous la corrigez, vous obtenez un dépôt unique, qui constitue la totalité de la valeur d'ajustement, dans le mois en cours. Il s'agit d'une transaction du mois en cours.

      La banque ne: change pas d'histoire; appliquer des intérêts pour chacun des mois historiques; rappeler les relevés bancaires historiques; republier les relevés bancaires historiques. Non, sauf peut-être dans les pays du tiers monde.

    • Les mêmes principes s'appliquent aux systèmes de contrôle des stocks. Il maintient la raison.

  5. Tous les systèmes comptables réels (c'est-à-dire ceux qui sont accrédités par l'autorité d'audit dans le pays concerné, par opposition aux "packages" Mickey Mouse qui abondent) utilisent un système de double entrée pour les transactions, précisément parce qu'il empêche une multitude d'erreurs, le dont le plus important est que les fonds ne se "perdent" pas. Cela nécessite un grand livre et une comptabilité en partie double.

    • Vous ne l'avez pas demandé, vous n'en avez pas besoin, donc je ne le décris pas ici. Mais souvenez-vous-en, au cas où l'argent "manquerait", car c'est ce que vous devrez mettre en œuvre, pas une solution de pansement; pas encore un autre "package" non accrédité.

    Cette réponse répond à la question qui est posée, qui est et non la comptabilité à double entrée.
    Pour un traitement complet de ce sujet (modèle de données détaillé; exemples de transactions comptables; lignes affectées; et exemples de code SQL), reportez-vous à cette Q&R:
    Modèle de données relationnelles pour la comptabilité à double entrée.

  6. Les principaux problèmes qui affectent les performances n'entrent pas dans le cadre de cette question, ils concernent la mise en œuvre ou non d'une véritable base de données relationnelle (par exemple, un système de classement des enregistrements des années 1960, caractérisé par Record IDs, Déployé dans un conteneur de base de données SQL pour plus de commodité).

    • L'utilisation de clés relationnelles authentiques, etc. maintiendra des performances élevées, quelle que soit la population des tables.

    • Inversement, un RFS fonctionnera mal, il ne peut tout simplement pas fonctionner. "Échelle", lorsqu'il est utilisé dans le contexte d'une RFS, est un terme frauduleux: il cache la cause et cherche à s'attaquer à tout sauf à la cause. Plus important encore, ces systèmes n'ont rien de l'intégrité relationnelle; le pouvoir relationnel; ou la vitesse relationnelle, d'un système relationnel.

La mise en oeuvre

Modèle de données relationnelles • Solde du compte

Acct

Modèle de données relationnelles • Inventaire

Inv

Notation

  • Tous mes modèles de données sont rendus dans IDEF1X, la norme de modélisation des bases de données relationnelles depuis 1993.

  • Mon Introduction à IDEF1X est une lecture essentielle pour ceux qui découvrent le Modèle relationnel, ou sa méthode de modélisation. Notez que les modèles IDEF1X sont riches en détails et en précision, montrant tous les détails requis, tandis que les modèles maison en ont beaucoup moins. Ce qui signifie que la notation doit être comprise.

Contenu

  1. Pour chaque compte, il y aura une ClosingBalance, dans une table AccountStatement (une ligne par AccountNo par mois), avec la date du relevé (généralement le premier jour du mois) ) et autres détails de la déclaration.

    • Ce n'est pas un doublon car il est demandé à des fins d'audit et de bon sens.

      Pour l'inventaire, il s'agit d'une colonne QtyOnHand, dans la table PartAudit (une ligne par PartCode par mois)

    • Il a une valeur supplémentaire, car il limite la portée des lignes de transaction à interroger à le mois en cours

      • Encore une fois, si votre table est relationnelle, la clé primaire de AccountTransaction sera (AccountNo, Transaction DateTime) qui récupérera les transactions à des vitesses en millisecondes.

      • Alors que pour un système de classement des enregistrements, la "clé primaire" sera TransactionID, et vous récupérerez le mois en cours par date de transaction, qui peut ou non être indexé correctement, et les lignes requises seront réparties sur le fichier. Dans tous les cas à des vitesses bien inférieures aux ClusteredIndex, et en raison de la propagation, cela entraînera un balayage de table.

  2. La table AccountTransaction reste simple (la notion réelle d'une transaction de compte bancaire est simple). Il a une seule colonne Amount positive.

  3. Pour chaque Account, le CurrentBalance est:

    • le AccountStatement.ClosingBalance du mois précédent, daté du premier du mois suivant pour plus de commodité

      (pour l'inventaire, le PartAudit.QtyOnHand)

    • plus la somme du AccountTransaction.Amounts du mois en cours, où le TransactionType indique un dépôt

      (pour l'inventaire, le PartMovement.Quantity)

    • moins la SOMME du AccountTransaction.Amounts du mois en cours, où le "MovementType indique un retrait.

  4. Dans cette méthode, les AccountTransactions du mois en cours, uniquement, sont dans un état de flux, ils doivent donc être dérivés . Tous les mois précédents sont publiés et clôturés, donc le chiffre d'audit doit être utilisé .

  5. Les anciennes lignes de la table AccountTransaction peuvent être purgées. Plus de dix ans pour l'argent public, cinq ans sinon, un an pour les systèmes de clubs de loisirs.

  6. Bien entendu, il est essentiel que tout code relatif aux systèmes comptables utilise des normes OLTP authentiques et des transactions SQL ACID authentiques).

  7. Cette conception intègre toutes les considérations de performances au niveau de la portée (si cela n'est pas évident, veuillez demander une extension). La mise à l'échelle à l'intérieur de la base de données n'est pas un problème, tous les problèmes de mise à l'échelle qui subsistent sont honnêtement en dehors de la base de données.


Conseils correctifs

Ces éléments doivent être déclarés uniquement parce que des conseils incorrects ont été fournis dans de nombreuses réponses SO (et majoritairement votées démocratiquement, bien sûr)), et Internet regorge d'informations incorrectes. conseils (les amateurs adorent publier leurs "vérités" subjectives):

  1. Évidemment, certaines personnes ne comprennent pas que j'ai donné une méthode en termes techniques, pour fonctionner contre un modèle de données clair. En tant que tel, il ne s'agit pas d'un pseudo-code pour une application spécifique dans un pays spécifique. La méthode est destinée aux développeurs compétents, elle n'est pas suffisamment détaillée pour ceux qui doivent être menés par la main.

    • Ils ne comprennent pas non plus que la période de coupure d'un mois est un exemple : si votre coupure aux fins de l'administration fiscale est trimestrielle, alors en tous les moyens, utilisez une coupure trimestrielle; si la seule exigence légale dont vous disposez est annuelle, utilisez annuelle.

    • Même si votre coupure est trimestrielle à des fins externes ou de conformité, l'entreprise peut très bien choisir une coupure mensuelle, à des fins d'audit interne et d'intégrité (c'est-à-dire pour maintenir la durée de la période de l'état de flux au minimum) .

      Par exemple. en Australie, la coupure du bureau des impôts pour les entreprises est trimestrielle, mais les grandes entreprises interrompent leur contrôle des stocks tous les mois (cela évite d'avoir à chasser les erreurs sur une longue période).

      Par exemple. les banques ont des obligations de conformité légale mensuellement, elles effectuent donc un audit interne sur les chiffres et clôturent les livres mensuellement.

    • Dans les pays primitifs et les États voyous, les banques maintiennent leur période de flux au maximum, à des fins néfastes évidentes. Certains d'entre eux ne font que leurs rapports de conformité chaque année. C'est une des raisons pour lesquelles les banques australiennes n'échouent pas.

  2. Dans la table AccountTransaction, n'utilisez pas de négatif/positif dans la colonne Montant. L'argent a toujours une valeur positive, il n'y a rien de tel que vingt dollars négatifs (ou que vous me devez moins cinquante dollars), puis vous vous rendez compte que les doubles négatifs signifient autre chose.

  3. La direction du mouvement, ou ce que vous allez faire avec les fonds, est un fait distinct et distinct (pour le AccountTransaction.Amount). Ce qui nécessite une colonne distincte (deux faits dans une donnée enfreignent les règles de normalisation, avec pour conséquence qu'elle introduit de la complexité dans le code).

    • Implémentez une table de référence TransactionType, dont la clé primaire est (D, W) Pour le dépôt/retrait comme point de départ. À mesure que le système se développe, ajoutez simplement (A, a, F, w) Pour le crédit d'ajustement; Débit d'ajustement; Frais bancaires; ATM_Withdrawal; etc.

    • Aucun changement de code requis.

  4. Dans certains pays primitifs, les exigences en matière de litige stipulent que dans tout rapport répertoriant les transactions, un total cumulé doit être indiqué sur chaque ligne. (Remarque, il ne s'agit pas d'une exigence d'audit parce que celles-ci sont supérieures [(voir la méthode ci-dessus) à l'exigence du tribunal; les auditeurs sont un peu moins stupides que les avocats; etc.)

    De toute évidence, je ne contesterais pas une exigence judiciaire. Le problème est que les codeurs primitifs traduisent cela en: oh, oh, nous devons implémenter unAccountTransaction.CurrentBalance colonne. Ils ne comprennent pas que:

    • l'exigence d'imprimer une colonne sur un rapport n'est pas une obligation de stocker une valeur dans la base de données

    • un total cumulé de toute nature est une valeur dérivée, et il est facilement codé (posez une question si ce n'est pas facile pour vous). Implémentez simplement le code requis dans le rapport.

    • mettre en œuvre le total cumulé, par exemple. AccountTransaction.CurrentBalance En tant que colonne provoque des problèmes horribles:

      • introduit une colonne dupliquée, car elle est dérivable. Interrompt la normalisation. Introduit une anomalie de mise à jour.

      • l'anomalie de mise à jour: chaque fois qu'une transaction est insérée historiquement ou qu'un AccountTransaction.Amount est modifié, tous les AccountTransaction.CurrentBalances de cette date au présent doivent être recalculés et mis à jour.

    • dans le cas ci-dessus, le rapport déposé auprès des tribunaux est désormais obsolète (chaque rapport de données en ligne est obsolète au moment de son impression). C'est à dire. impression; la revue; modifier la transaction; réimpression; revoir, jusqu'à ce que vous soyez satisfait. Cela n'a aucun sens en tout cas.

    • c'est pourquoi, dans les pays moins primitifs, les tribunaux n'acceptent aucun vieux papier imprimé, ils n'acceptent que les chiffres publiés, par exemple. Les relevés bancaires, qui sont déjà soumis aux exigences d'audit (voir la méthode ci-dessus), et qui ne peuvent pas être rappelés ou modifiés et réimprimés.


Commentaires

Alex:
oui le code serait agréable à regarder, merci. Même peut-être un exemple de "boutique de seaux" pour que les gens puissent voir le schéma de départ une fois pour toutes, rendrait le monde bien meilleur.

Pour le modèle de données ci-dessus.

Code • Signaler le solde actuel

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"

En dénormalisant le journal des transactions, je négocie le formulaire normal pour des requêtes plus pratiques et moins de changements dans les vues/vues matérialisées lorsque j'ajoute plus de types tx

Dieu aide moi.

  1. Lorsque vous allez à l'encontre des normes, vous vous placez dans une position du tiers-monde, où des choses qui ne sont pas censées se briser, qui ne se brisent jamais dans les pays du premier monde, se brisent.

    Ce n'est probablement pas une bonne idée de chercher la bonne réponse auprès d'une autorité, puis de s'y opposer, ou de plaider pour votre méthode inférieure aux normes.

  2. La dénormalisation (ici) provoque une anomalie de mise à jour, la colonne dupliquée, qui peut être dérivée de TransactionTypeCode. Vous voulez un codage facile, mais vous êtes prêt à le coder en deux endroits, plutôt qu'en un. C'est exactement le type de code sujet aux erreurs.

    Une base de données entièrement normalisée selon le Dr E F Codd Modèle relationnel fournit le code le plus simple, le plus logique et le plus simple. (Dans mon travail, je garantis contractuellement que chaque rapport peut être traité par un seul SELECT.)

  3. ENUM n'est pas SQL. (Les suites NONsql gratuites ne sont pas conformes à SQL, mais elles ont des extras qui ne sont pas requis dans SQL.) Si jamais votre application passe à une plate-forme SQL commerciale, vous devrez réécrire tous ces ENUMs en tant que tables LookUp ordinaires. Avec une CHAR(1) ou un INT comme PK. Ensuite, vous apprécierez qu'il s'agit en fait d'une table avec un PK.

  4. Une erreur a une valeur de zéro (elle a également des conséquences négatives). Une vérité a une valeur de un. Je n'échangerais pas un contre zéro. Ce n'est donc pas un compromis. C'est juste votre décision de développement.

111
PerformanceDBA

C'est assez subjectif. Les choses que je suggérerais de prendre en compte sont:

  1. Combien de comptes existe-t-il actuellement?
  2. Combien de comptes prévoyez-vous avoir à l'avenir?
  3. Quelle valeur accordez-vous à l'évolutivité?
  4. Est-il difficile de mettre à jour votre base de données et votre code pour suivre le solde comme son propre champ?
  5. Y a-t-il des problèmes de développement plus immédiats auxquels il faut répondre?

En termes de mérites des deux approches proposées, la somme des valeurs transactionnelles à la demande sera probablement l'approche la plus facile/plus rapide à mettre en œuvre.

Cependant, il n'évolue pas aussi bien que le maintien du solde du compte courant en tant que champ dans la base de données et sa mise à jour au fur et à mesure. Et cela augmente quelque peu le temps de traitement global de vos transactions, car chaque transaction doit exécuter une requête pour calculer le solde du compte courant avant de pouvoir continuer. Dans la pratique, il peut s'agir de petites préoccupations, sauf si vous avez un très grand nombre de comptes/transactions ou si vous vous y attendez dans un avenir très proche.

L'inconvénient de la deuxième approche est qu'il faudra probablement plus de temps/d'efforts de développement pour la configuration initiale, et peut nécessiter que vous réfléchissiez à la façon dont vous synchronisez les transactions au sein d'un compte pour vous assurer que chacun voit et met à jour le solde avec précision de tout temps.

Donc, cela se résume principalement aux besoins du projet, au moment où le temps de développement est le mieux dépensé pour le moment, et à savoir s'il vaut la peine de pérenniser la solution maintenant plutôt que de mettre en œuvre la deuxième approche plus tard, lorsque les performances et l'évolutivité deviennent réelles, plutôt que des problèmes théoriques.

1
aroth