एक साधारण बैंक स्कीमा लिखना: मुझे अपने लेनदेन के इतिहास के साथ अपने संतुलन को कैसे रखना चाहिए?


57

मैं एक साधारण बैंक डेटाबेस के लिए स्कीमा लिख ​​रहा हूं। यहाँ बुनियादी विनिर्देश हैं:

  • डेटाबेस एक उपयोगकर्ता और मुद्रा के खिलाफ लेनदेन को संग्रहीत करेगा।
  • प्रत्येक उपयोगकर्ता के पास प्रति मुद्रा एक शेष राशि है, इसलिए प्रत्येक शेष राशि किसी दिए गए उपयोगकर्ता और मुद्रा के खिलाफ सभी लेनदेन का योग है।
  • एक संतुलन नकारात्मक नहीं हो सकता।

बैंक एप्लिकेशन अपने डेटाबेस के साथ विशेष रूप से संग्रहीत प्रक्रियाओं के माध्यम से संचार करेगा।

मुझे उम्मीद है कि इस डेटाबेस में प्रति दिन सैकड़ों हजारों नए लेनदेन स्वीकार किए जाएंगे, साथ ही साथ परिमाण के उच्च क्रम पर प्रश्नों को संतुलित किया जाएगा। बहुत जल्दी संतुलन बनाने के लिए मुझे उन्हें पूर्व-एकत्र करने की आवश्यकता है। उसी समय, मुझे यह गारंटी देने की आवश्यकता है कि एक संतुलन कभी भी इसके लेनदेन के इतिहास का खंडन नहीं करता है।

मेरे विकल्प हैं:

  1. एक अलग balancesटेबल रखें और निम्न में से एक करें:

    1. दोनों transactionsऔर balancesतालिकाओं के लिए लेनदेन लागू करें । TRANSACTIONमेरी संग्रहीत कार्यविधि परत में तर्क का उपयोग करें ताकि यह सुनिश्चित हो सके कि संतुलन और लेनदेन हमेशा सिंक में हैं। ( जैक द्वारा समर्थित )

    2. लेन-देन को transactionsतालिका में लागू करें और एक ट्रिगर करें जो balancesलेनदेन की राशि के साथ मेरे लिए तालिका को अपडेट करता है ।

    3. लेन-देन को balancesतालिका में लागू करें और एक ट्रिगर करें जो transactionsलेनदेन की राशि के साथ मेरे लिए तालिका में एक नई प्रविष्टि जोड़ता है ।

    मुझे यह सुनिश्चित करने के लिए सुरक्षा-आधारित दृष्टिकोणों पर भरोसा करना होगा कि संग्रहीत प्रक्रियाओं के बाहर कोई बदलाव नहीं किया जा सकता है। अन्यथा, उदाहरण के लिए, कुछ प्रक्रिया सीधे लेनदेन को transactionsतालिका में सम्मिलित कर सकती है और योजना 1.3के तहत प्रासंगिक संतुलन सिंक से बाहर हो जाएगा।

  2. एक balancesअनुक्रमित दृश्य है जो लेनदेन को उचित रूप से एकत्रित करता है। भंडारण इंजन द्वारा बैलेंस की गारंटी उनके लेनदेन के साथ रहने के लिए दी जाती है, इसलिए मुझे इसकी गारंटी देने के लिए सुरक्षा-आधारित दृष्टिकोणों पर भरोसा करने की आवश्यकता नहीं है। दूसरी ओर, मैं संतुलन लागू नहीं कर सकता क्योंकि अब भी गैर-नकारात्मक हो सकता है - यहां तक ​​कि अनुक्रमित विचार - भी CHECKअड़चन नहीं हो सकते । ( डेनी द्वारा समर्थित )

  3. सिर्फ एक transactionsतालिका है लेकिन एक अतिरिक्त कॉलम के साथ शेष राशि को सही तरीके से लेन-देन करने के लिए प्रभावी है। इस प्रकार, एक उपयोगकर्ता और मुद्रा के लिए नवीनतम लेनदेन रिकॉर्ड में उनका वर्तमान संतुलन भी शामिल है। ( एंड्रयू द्वारा नीचे सुझाया गया ; वैरिक द्वारा प्रस्तावित संस्करण )

जब मैंने पहली बार इस समस्या से निपटा, तो मैंने इन दो चर्चाओं को पढ़ा और विकल्प पर निर्णय लिया 2। संदर्भ के लिए, आप इसके बारे में एक नंगे हड्डियों कार्यान्वयन देख सकते हैं यहां

  • क्या आपने एक उच्च लोड प्रोफ़ाइल के साथ एक डेटाबेस को इस तरह डिज़ाइन या प्रबंधित किया है? आपकी इस समस्या का हल क्या था?

  • क्या आपको लगता है कि मैंने सही डिज़ाइन पसंद किया है? क्या मुझे कुछ भी ध्यान में रखना चाहिए?

    उदाहरण के लिए, मुझे पता है कि transactionsतालिका में स्कीमा परिवर्तन से मुझे balancesदृश्य के पुनर्निर्माण की आवश्यकता होगी । यहां तक ​​कि अगर मैं डेटाबेस को छोटा रखने के लिए लेन-देन कर रहा हूं (जैसे उन्हें कहीं और ले जाकर और उन्हें सारांश लेनदेन के साथ बदलकर), तो हर स्कीमा अपडेट के साथ दसियों लाखों लेनदेन के दृश्य को फिर से बनाना, संभवतः तैनाती के प्रति काफी डाउनटाइम का मतलब होगा।

  • यदि अनुक्रमित दृश्य जाने का रास्ता है, तो मैं कैसे गारंटी दे सकता हूं कि कोई संतुलन नकारात्मक नहीं है?


अभिलेखागार लेनदेन:

मुझे ऊपर दिए गए अभिलेखों और "सारांश लेनदेन" को संग्रहीत करने पर थोड़ा विस्तार से बताएं। सबसे पहले, इस तरह के एक उच्च-लोड प्रणाली में नियमित संग्रह एक आवश्यकता होगी। मैं पुराने लेनदेन को कहीं और स्थानांतरित करने की अनुमति देते हुए संतुलन और उनके लेनदेन इतिहास के बीच स्थिरता बनाए रखना चाहता हूं। ऐसा करने के लिए, मैं प्रत्येक राशि को प्रति उपयोगकर्ता और मुद्रा के सारांश के साथ संग्रहीत लेन-देन की जगह दूंगा।

इसलिए, उदाहरण के लिए, लेन-देन की यह सूची:

user_id    currency_id      amount    is_summary
------------------------------------------------
      3              1       10.60             0
      3              1      -55.00             0
      3              1      -12.12             0

दूर संग्रहीत है और इसके साथ प्रतिस्थापित किया गया है:

user_id    currency_id      amount    is_summary
------------------------------------------------
      3              1      -56.52             1

इस तरह, संग्रहीत लेनदेन के साथ एक संतुलन पूर्ण और सुसंगत लेनदेन इतिहास रखता है।


1
यदि आप विकल्प 2 (जो मुझे लगता है कि क्लीनर है) चुनते हैं, तो pgcon.org/2008/schedule/attachments/… पर एक नज़र डालें "कुशलतापूर्वक" भौतिक विचारों को कैसे लागू करें। विकल्प 1 के लिए, डेटाबेस प्रोफेशनल्स के लिए हैनस और कोप्पेलार्स के एप्लाइड मैथमेटिक्स के अध्याय 11 (शीर्षक के बारे में चिंता न करें) एक विचार प्राप्त करने में सहायक होगा कि कैसे "संक्रमण बाधाओं" को कुशलता से लागू किया जाए। पहला लिंक PostgreSQL के लिए है और दूसरा Oracle के लिए, लेकिन तकनीकों को किसी भी उचित डेटाबेस सिस्टम के लिए काम करना चाहिए।
जेपी

सिद्धांत रूप में आप # 3 करना चाहते हैं। "रनिंग बैलेंस" करने का सही तरीका यह है कि प्रत्येक लेनदेन के लिए एक बैलेंस असाइन किया जाए। सुनिश्चित करें कि आप निश्चित रूप से या तो सीरियल आईडी (पसंदीदा) या टाइमस्टैम्प के साथ लेनदेन का आदेश दे सकते हैं। आप वास्तव में एक चल रहे संतुलन को "गणना" करने वाले नहीं हैं।
pbreitenbach

जवाबों:


15

मैं लेखांकन से परिचित नहीं हूं, लेकिन मैंने सूची-प्रकार के वातावरण में कुछ समान समस्याओं को हल किया। मैं लेन-देन के साथ एक ही पंक्ति में चल रहे योगों को संग्रहीत करता हूं। मैं बाधाओं का उपयोग कर रहा हूं, ताकि मेरा डेटा उच्च संगामिति के तहत भी गलत न हो। मैंने निम्न समाधान को 2009 में वापस लिखा है :

कुल योग की गणना बहुत धीमी है, चाहे आप इसे कर्सर के साथ करें या त्रिकोणीय जुड़ाव के साथ करें। किसी कॉलम में रनिंग योग को स्टोर करना, विशेष रूप से यदि आप इसे अक्सर चुनते हैं, तो इसे बहुत लुभावना है। हालाँकि, जब आप सामान्य करते हैं, तो आपको अपने असामान्य डेटा की अखंडता की गारंटी देने की आवश्यकता होती है। सौभाग्य से, आप बाधाओं के साथ चल रहे योगों की अखंडता की गारंटी दे सकते हैं - जब तक आपके सभी बाधाओं पर भरोसा किया जाता है, आपके सभी चल रहे योग सही हैं। इस तरह से आप आसानी से यह सुनिश्चित कर सकते हैं कि वर्तमान संतुलन (चल रहा योग) कभी भी नकारात्मक नहीं है - अन्य तरीकों से लागू करना भी बहुत धीमा हो सकता है। निम्नलिखित स्क्रिप्ट तकनीक प्रदर्शित करती है।

CREATE TABLE Data.Inventory(InventoryID INT NOT NULL IDENTITY,
  ItemID INT NOT NULL,
  ChangeDate DATETIME NOT NULL,
  ChangeQty INT NOT NULL,
  TotalQty INT NOT NULL,
  PreviousChangeDate DATETIME NULL,
  PreviousTotalQty INT NULL,
  CONSTRAINT PK_Inventory PRIMARY KEY(ItemID, ChangeDate),
  CONSTRAINT UNQ_Inventory UNIQUE(ItemID, ChangeDate, TotalQty),
  CONSTRAINT UNQ_Inventory_Previous_Columns 
     UNIQUE(ItemID, PreviousChangeDate, PreviousTotalQty),
  CONSTRAINT FK_Inventory_Self FOREIGN KEY(ItemID, PreviousChangeDate, PreviousTotalQty)
    REFERENCES Data.Inventory(ItemID, ChangeDate, TotalQty),
  CONSTRAINT CHK_Inventory_Valid_TotalQty CHECK(
         TotalQty >= 0 
     AND (TotalQty = COALESCE(PreviousTotalQty, 0) + ChangeQty)
  ),
  CONSTRAINT CHK_Inventory_Valid_Dates_Sequence CHECK(PreviousChangeDate < ChangeDate),
  CONSTRAINT CHK_Inventory_Valid_Previous_Columns CHECK(
        (PreviousChangeDate IS NULL AND PreviousTotalQty IS NULL)
     OR (PreviousChangeDate IS NOT NULL AND PreviousTotalQty IS NOT NULL)
  )
);

-- beginning of inventory for item 1
INSERT INTO Data.Inventory(ItemID,
  ChangeDate,
  ChangeQty,
  TotalQty,
  PreviousChangeDate,
  PreviousTotalQty)
VALUES(1, '20090101', 10, 10, NULL, NULL);

-- cannot begin the inventory for the second time for the same item 1
INSERT INTO Data.Inventory(ItemID,
  ChangeDate,
  ChangeQty,
  TotalQty,
  PreviousChangeDate,
  PreviousTotalQty)
VALUES(1, '20090102', 10, 10, NULL, NULL);


Msg 2627, Level 14, State 1, Line 10

Violation of UNIQUE KEY constraint 'UNQ_Inventory_Previous_Columns'. 
Cannot insert duplicate key in object 'Data.Inventory'.

The statement has been terminated.


-- add more
DECLARE @ChangeQty INT;
SET @ChangeQty = 5;

INSERT INTO Data.Inventory(ItemID,
  ChangeDate,
  ChangeQty,
  TotalQty,
  PreviousChangeDate,
  PreviousTotalQty)

SELECT TOP 1 ItemID, '20090103', @ChangeQty, TotalQty + @ChangeQty, ChangeDate, TotalQty
  FROM Data.Inventory
  WHERE ItemID = 1
  ORDER BY ChangeDate DESC;

SET @ChangeQty = 3;

INSERT INTO Data.Inventory(ItemID,
  ChangeDate,
  ChangeQty,
  TotalQty,
  PreviousChangeDate,
  PreviousTotalQty)

SELECT TOP 1 ItemID, '20090104', @ChangeQty, TotalQty + @ChangeQty, ChangeDate, TotalQty
  FROM Data.Inventory
  WHERE ItemID = 1
  ORDER BY ChangeDate DESC;

SET @ChangeQty = -4;

INSERT INTO Data.Inventory(ItemID,
  ChangeDate,
  ChangeQty,
  TotalQty,
  PreviousChangeDate,
  PreviousTotalQty)

SELECT TOP 1 ItemID, '20090105', @ChangeQty, TotalQty + @ChangeQty, ChangeDate, TotalQty
  FROM Data.Inventory
  WHERE ItemID = 1
  ORDER BY ChangeDate DESC;

-- try to violate chronological order
SET @ChangeQty = 5;

INSERT INTO Data.Inventory(ItemID,
  ChangeDate,
  ChangeQty,
  TotalQty,
  PreviousChangeDate,
  PreviousTotalQty)

SELECT TOP 1 ItemID, '20081231', @ChangeQty, TotalQty + @ChangeQty, ChangeDate, TotalQty
  FROM Data.Inventory
  WHERE ItemID = 1
  ORDER BY ChangeDate DESC;

Msg 547, Level 16, State 0, Line 4

The INSERT statement conflicted with the CHECK constraint 
"CHK_Inventory_Valid_Dates_Sequence". 
The conflict occurred in database "Test", table "Data.Inventory".

The statement has been terminated.

SELECT ChangeDate,
  ChangeQty,
  TotalQty,
  PreviousChangeDate,
  PreviousTotalQty
FROM Data.Inventory ORDER BY ChangeDate;

ChangeDate              ChangeQty   TotalQty    PreviousChangeDate      PreviousTotalQty
----------------------- ----------- ----------- ----------------------- -----
2009-01-01 00:00:00.000 10          10          NULL                    NULL
2009-01-03 00:00:00.000 5           15          2009-01-01 00:00:00.000 10
2009-01-04 00:00:00.000 3           18          2009-01-03 00:00:00.000 15
2009-01-05 00:00:00.000 -4          14          2009-01-04 00:00:00.000 18


-- try to change a single row, all updates must fail
UPDATE Data.Inventory SET ChangeQty = ChangeQty + 2 WHERE InventoryID = 3;
UPDATE Data.Inventory SET TotalQty = TotalQty + 2 WHERE InventoryID = 3;

-- try to delete not the last row, all deletes must fail
DELETE FROM Data.Inventory WHERE InventoryID = 1;
DELETE FROM Data.Inventory WHERE InventoryID = 3;

-- the right way to update
DECLARE @IncreaseQty INT;

SET @IncreaseQty = 2;

UPDATE Data.Inventory 
SET 
     ChangeQty = ChangeQty 
   + CASE 
        WHEN ItemID = 1 AND ChangeDate = '20090103' 
        THEN @IncreaseQty 
        ELSE 0 
     END,
  TotalQty = TotalQty + @IncreaseQty,
  PreviousTotalQty = PreviousTotalQty + 
     CASE 
        WHEN ItemID = 1 AND ChangeDate = '20090103' 
        THEN 0 
        ELSE @IncreaseQty 
     END
WHERE ItemID = 1 AND ChangeDate >= '20090103';

SELECT ChangeDate,
  ChangeQty,
  TotalQty,
  PreviousChangeDate,
  PreviousTotalQty
FROM Data.Inventory ORDER BY ChangeDate;

ChangeDate              ChangeQty   TotalQty    PreviousChangeDate      PreviousTotalQty
----------------------- ----------- ----------- ----------------------- ----------------
2009-01-01 00:00:00.000 10          10          NULL                    NULL
2009-01-03 00:00:00.000 7           17          2009-01-01 00:00:00.000 10
2009-01-04 00:00:00.000 3           20          2009-01-03 00:00:00.000 17
2009-01-05 00:00:00.000 -4          16          2009-01-04 00:00:00.000 20

14

ग्राहकों को 0 से कम शेष राशि की अनुमति नहीं देना एक व्यावसायिक नियम है (जो कि ओवर ड्राफ्ट जैसी चीजों के लिए शुल्क के रूप में जल्दी से बदल जाएगा, बैंक अपने पैसे का अधिकांश हिस्सा कैसे बनाते हैं)। जब लेन-देन के इतिहास में पंक्तियाँ डाली जाती हैं, तो आप इसे अनुप्रयोग प्रसंस्करण में संभालना चाहते हैं। खासकर जब आप ओवरड्राफ्ट सुरक्षा वाले कुछ ग्राहकों के साथ समाप्त हो सकते हैं और कुछ शुल्क ले रहे हैं और कुछ नकारात्मक मात्रा में प्रवेश करने की अनुमति नहीं दे रहे हैं।

अब तक मुझे यह पसंद है कि आप इसके साथ कहाँ जा रहे हैं, लेकिन अगर यह एक वास्तविक परियोजना (स्कूल नहीं) के लिए है, तो व्यापार नियमों में बहुत सारे विचारों का एक नरक होने की आवश्यकता है, आदि। एक बार जब आप एक बैंकिंग प्रणाली प्राप्त कर लेते हैं। और वहाँ फिर से तैयार होने के लिए बहुत जगह नहीं है क्योंकि लोगों के पास उनके पैसे तक पहुंचने के बारे में बहुत विशिष्ट कानून हैं।


1
मैं देख सकता हूं कि संतुलन की कमी वास्तव में एक व्यावसायिक नियम क्यों होनी चाहिए। डेटाबेस केवल एक लेन-देन सेवा प्रदान कर रहा है, और यह उपयोगकर्ता के लिए यह तय करना है कि इसके साथ क्या करना है।
निक चम्मास

आप जैक की टिप्पणियों के बारे में क्या सोचते हैं कि दो तालिकाओं का उपयोग करने से व्यापार तर्क बदलने या लागू करने में डेवलपर्स को अधिक लचीलापन मिलता है? इसके अलावा, क्या आपके पास अनुक्रमित विचारों के साथ कोई प्रत्यक्ष अनुभव है जो इन चिंताओं को मान्य या चुनौती देता है ?
निक चम्मास

1
मैं यह नहीं कहूंगा कि दो तालिकाओं के होने से आपको लचीलापन मिलेगा और व्यावसायिक तर्क लागू हो रहे हैं। यह डेटा संग्रह करने में आपको अधिक लचीलापन देता है। हालांकि एक बैंक के रूप में (कम से कम अमेरिका में) आपको कानून मिले हैं जो कहते हैं कि आपको कितना डेटा रखने की आवश्यकता है। आप परीक्षण करना चाहते हैं कि प्रदर्शन शीर्ष पर दृश्य के साथ कैसा दिखता है, साथ ही साथ यह भी ध्यान रखें कि यदि आपके पास अनुक्रमित दृश्य है तो आप अंतर्निहित तालिकाओं के स्कीमा को बदल नहीं सकते हैं। बस एक और बात सोचने की है।
मर्डेनी सेप

अनुक्रमित दृश्य का उपयोग करते समय लेख में उल्लिखित सभी आइटम किसी भी चीज़ के लिए वैध चिंताएं हैं।
मर्डनी

1
स्पष्ट करने के लिए: IMO एक ट्रांसेक्शनल एपीआई व्यापार तर्क को लागू करने में अधिक लचीलापन देता है (दो तालिकाओं में नहीं)। इस मामले में मैं भी दो तालिकाओं के पक्ष में रहूंगा (कम से कम हमें जो जानकारी अभी तक दी गई है), क्योंकि अनुक्रमित दृश्य दृष्टिकोण के साथ प्रस्तावित व्यापार-ऑफ्स के कारण (उदाहरण के लिए संतुलन को लागू करने के लिए DRI का उपयोग नहीं कर सकते हैं> 0 व्यवसाय नियम)
जैक डगलस

13

विचार करने के लिए थोड़ा अलग दृष्टिकोण (आपके 2 विकल्प के समान ) की परिभाषा तालिका के साथ सिर्फ लेन-देन तालिका है:

CREATE TABLE Transaction (
      UserID              INT
    , CurrencyID          INT 
    , TransactionDate     DATETIME  
    , OpeningBalance      MONEY
    , TransactionAmount   MONEY
);

आप एक ट्रांजेक्शन आईडी / ऑर्डर भी चाहते हैं, ताकि आप एक ही तारीख से दो लेन-देन कर सकें और अपनी पुनर्प्राप्ति क्वेरी में सुधार कर सकें।

वर्तमान शेष राशि प्राप्त करने के लिए, आपको केवल अंतिम रिकॉर्ड प्राप्त करना होगा।

अंतिम रिकॉर्ड प्राप्त करने के तरीके :

/* For a single User/Currency */
Select TOP 1 *
FROM dbo.Transaction
WHERE UserID = 3 and CurrencyID = 1
ORDER By TransactionDate desc

/* For multiple records ie: to put into a view (which you might want to index) */
SELECT
    C.*
FROM
    (SELECT 
        *, 
        ROW_NUMBER() OVER (
           PARTITION BY UserID, CurrencyID 
           ORDER BY TransactionDate DESC
        ) AS rnBalance 
    FROM Transaction) C
WHERE
    C.rnBalance = 1
ORDER BY
    C.UserID, C.CurrencyID

विपक्ष:

  • लेन-देन को अनुक्रम से बाहर करते समय (यानी: किसी समस्या / गलत शुरुआती संतुलन को ठीक करने के लिए), आपको बाद के लेनदेन के लिए अपडेट को कैस्केड करना पड़ सकता है।
  • उपयोगकर्ता / मुद्रा के लिए लेनदेन को एक सटीक संतुलन बनाए रखने के लिए क्रमबद्ध करना होगा।

    -- Example of getting the current balance and locking the 
    -- last record for that User/Currency.
    -- This lock will be freed after the Stored Procedure completes.
    SELECT TOP 1 @OldBalance = OpeningBalance + TransactionAmount  
    FROM dbo.Transaction with (rowlock, xlock)   
    WHERE UserID = 3 and CurrencyID = 1  
    ORDER By TransactionDate DESC;
    

पेशेवरों:

  • अब आपको दो अलग-अलग तालिकाएँ नहीं रखनी होंगी ...
  • आप आसानी से शेष राशि को सत्यापित कर सकते हैं, और जब शेष राशि सिंक से बाहर हो जाती है तो आप ठीक से पहचान सकते हैं जब यह अजीब से बाहर हो गया क्योंकि लेनदेन का इतिहास स्व दस्तावेज हो जाता है।

संपादित करें: वर्तमान संतुलन की पुनर्प्राप्ति पर कुछ नमूना प्रश्न और चुनाव को उजागर करने के लिए (धन्यवाद @ जेक डगलस)


3
इस SELECT TOP (1) ... ORDER BY TransactionDate DESCतरह से लागू करने के लिए यह बहुत मुश्किल होगा कि SQL सर्वर लेनदेन तालिका को लगातार स्कैन नहीं करता है। एलेक्स कुजनेत्सोव ने इसी तरह की डिजाइन समस्या के लिए यहां एक समाधान पोस्ट किया जो इस उत्तर को पूरी तरह से पूरक करता है।
निक चामास

2
+1 मैं एक समान दृष्टिकोण का उपयोग कर रहा हूं। BTW, हमें बहुत सावधान रहने की जरूरत है और सुनिश्चित करें कि हमारा कोड समवर्ती कार्यभार के तहत सही ढंग से काम करता है।
एके

12

इन दो चर्चाओं को पढ़ने के बाद, मैंने विकल्प 2 पर फैसला किया

उन चर्चाओं को भी पढ़ने के बाद, मुझे यकीन नहीं है कि आपने DRI समाधान के बारे में निर्णय लिया है जो आपके द्वारा उल्लिखित अन्य विकल्पों में से सबसे अधिक समझदार हैं:

लेनदेन और शेष तालिकाओं दोनों के लिए लेनदेन लागू करें। यह सुनिश्चित करने के लिए कि संग्रहीत और लेन-देन हमेशा सिंक में हों, मेरी संग्रहीत कार्यविधि परत में परिवहन तर्क का उपयोग करें।

इस तरह के समाधान के बहुत व्यावहारिक लाभ हैं यदि आपके पास अपने लेन-देन एपीआई के माध्यम से डेटा तक सभी पहुंच को प्रतिबंधित करने की लक्जरी है । आप DRI का बहुत महत्वपूर्ण लाभ खो देते हैं, यह है कि अखंडता की गारंटी डेटाबेस द्वारा दी जाती है, लेकिन पर्याप्त जटिलता के किसी भी मॉडल में कुछ व्यावसायिक नियम होंगे जो DRI द्वारा लागू नहीं किए जा सकते हैं

मैं डीआरआई का उपयोग करने की सलाह दूंगा जहां संभव हो कि आपके मॉडल को झुकने के बिना व्यावसायिक नियमों को लागू करना संभव हो सके:

भले ही मैं लेन-देन कर रहा हूं (उदाहरण के लिए उन्हें कहीं और ले जाकर और उन्हें सारांश लेनदेन के साथ बदलकर)

जैसे ही आप इस तरह से अपने मॉडल को प्रदूषित करने पर विचार करने लगते हैं, मुझे लगता है कि आप उस क्षेत्र में आगे बढ़ रहे हैं जहां DRI का लाभ आपके द्वारा पेश की जा रही कठिनाइयों से है। उदाहरण के लिए विचार करें कि सिद्धांत में आपकी अभिलेखीय प्रक्रिया में एक बग आपके स्वर्णिम नियम (जो हमेशा लेन-देन के योग के बराबर संतुलन ) को DRI समाधान के साथ चुपचाप तोड़ सकता है

जैसा कि मैं उन्हें देखता हूं, यहां लेन-देन के दृष्टिकोण के फायदों का सारांश है:

  • हमें यह वैसे भी करना चाहिए यदि संभव हो तो। इस विशेष समस्या के लिए आप जो भी समाधान चुनते हैं, वह आपको अधिक लचीलेपन और आपके डेटा पर नियंत्रण प्रदान करता है। सभी तर्क तब व्यापार तर्क के संदर्भ में "लेन-देन" बन जाते हैं, बजाय डेटाबेस तर्क के।
  • आप अपने मॉडल को साफ-सुथरा रख सकते हैं
  • आप व्यावसायिक नियमों की एक बहुत व्यापक श्रेणी और जटिलता को "लागू" कर सकते हैं (ध्यान दें कि "लागू" की अवधारणा डीआरआई की तुलना में एक शिथिल है)
  • आप अभी भी DRI का उपयोग कर सकते हैं जहाँ मॉडल को अधिक मजबूत अंतर्निहित अखंडता देने के लिए व्यावहारिक है - और यह आपके लेन-देन के तर्क पर जाँच के रूप में कार्य कर सकता है
  • प्रदर्शन के अधिकांश मुद्दे जो आपको परेशान कर रहे हैं वे पिघल जाएंगे
  • नई आवश्यकताओं को प्रस्तुत करना बहुत आसान हो सकता है - उदाहरण के लिए: विवादित लेनदेन के लिए जटिल नियम आपको शुद्ध डीआरआई दृष्टिकोण से दूर लाइन के नीचे मजबूर कर सकते हैं, जिसका अर्थ है बहुत सारे व्यर्थ प्रयास।
  • ऐतिहासिक डेटा का विभाजन या संग्रह बहुत कम जोखिम भरा और दर्दनाक हो जाता है

--edit

जटिलता या जोखिम को जोड़े बिना संग्रह करने की अनुमति देने के लिए, आप एक अलग सारांश तालिका में सारांश पंक्तियों को रखने के लिए चुन सकते हैं, लगातार उत्पन्न (@Andrew और @Garik से उधार)

उदाहरण के लिए, यदि सारांश मासिक हैं:

  • हर बार एक लेनदेन होता है (आपके एपीआई के माध्यम से) सारांश तालिका में एक अद्यतन या सम्मिलित होता है
  • सारांश तालिका को कभी संग्रहीत नहीं किया जाता है, लेकिन संग्रह लेनदेन सरल आ डिलीट (या ड्रॉप विभाजन?) के रूप में हो जाता है
  • सारांश तालिका में प्रत्येक पंक्ति में 'प्रारंभिक संतुलन' और 'राशि' शामिल हैं।
  • जाँच अवरोध जैसे कि 'शुरुआती शेष राशि' + 'राशि'> 0 और 'शेष राशि'> 0 को सारांश तालिका में लागू किया जा सकता है
  • सारांश पंक्तियों को एक मासिक बैच में डाला जा सकता है ताकि नवीनतम सारांश पंक्ति को लॉक करना आसान हो सके (चालू माह के लिए हमेशा एक पंक्ति होगी)

अपने संपादन के बारे में: तो आप इस सारांश तालिका को मुख्य शेष तालिका के साथ रखने का प्रस्ताव रखते हैं? क्या बैलेंस टेबल तब प्रभावी रूप से एक सारांश तालिका बन जाती है जिसमें अभी चालू माह का रिकॉर्ड होता है (क्योंकि दोनों एक ही तरह का डेटा संग्रहित करेंगे)? यदि मैंने सही तरीके से समझा है, तो क्यों न केवल शेष तालिका को सारांश तालिका पर उचित विभाजन के साथ बदल दिया जाए?
निक चामास

क्षमा करें आप सही हैं जो अस्पष्ट है - मेरा मतलब था कि शेष तालिका को हटा देना क्योंकि यह वर्तमान संतुलन प्राप्त करने के लिए सारांश तालिका पर हमेशा एक महत्वपूर्ण खोज होगी (एंड्रयूज सुझाव AFAIK के साथ सच नहीं है)। लाभ यह है कि पिछले समय में संतुलन की गणना करना आसान हो जाता है और गलत होने पर शेष राशि के लिए स्पष्ट ऑडिट ट्रेल होता है।
जैक डगलस

6

निक।

मुख्य विचार एक ही तालिका में संतुलन और लेनदेन रिकॉर्ड संग्रहीत कर रहा है। यह ऐतिहासिक रूप से मैंने सोचा था कि हुआ। तो इस मामले में हम केवल पिछले सारांश रिकॉर्ड का पता लगाकर शेष राशि प्राप्त कर सकते हैं।

 id   user_id    currency_id      amount    is_summary (or record_type)
----------------------------------------------------
  1       3              1       10.60             0
  2       3              1       10.60             1    -- summary after transaction 1
  3       3              1      -55.00             0
  4       3              1      -44.40             1    -- summary after transactions 1 and 3
  5       3              1      -12.12             0
  6       3              1      -56.52             1    -- summary after transactions 1, 3 and 5 

एक बेहतर संस्करण सारांश रिकॉर्डों की संख्या कम कर रहा है। हमारे पास दिन के अंत (और / या शुरू) में एक शेष रिकॉर्ड हो सकता है। जैसा कि आप जानते हैं कि प्रत्येक बैंक को operational dayइस दिन के लिए कुछ सारांश संचालन करने के लिए खोलना और बंद करना है। यह हमें हर दिन शेष रिकॉर्ड का उपयोग करके ब्याज की गणना करने में आसान बनाता है , उदाहरण के लिए:

user_id    currency_id      amount    is_summary    oper_date
--------------------------------------------------------------
      3              1       10.60             0    01/01/2011 
      3              1      -55.00             0    01/01/2011
      3              1      -44.40             1    01/01/2011 -- summary at the end of day (01/01/2011)
      3              1      -12.12             0    01/02/2011
      3              1      -56.52             1    01/02/2011 -- summary at the end of day (01/02/2011)

भाग्य।


4

आपकी आवश्यकताओं के आधार पर, विकल्प 1 सबसे अच्छा दिखाई देगा। हालाँकि, मेरे पास मेरा डिज़ाइन केवल लेन-देन तालिका में आवेषण की अनुमति होगा। और लेन-देन तालिका पर ट्रिगर है, वास्तविक समय संतुलन तालिका को अपडेट करने के लिए। आप इन तालिकाओं तक पहुंच को नियंत्रित करने के लिए डेटाबेस अनुमतियों का उपयोग कर सकते हैं।

इस दृष्टिकोण में, लेन-देन तालिका के साथ वास्तविक समय का संतुलन सिंक करने की गारंटी है। और इससे कोई फर्क नहीं पड़ता कि संग्रहीत प्रक्रियाओं या psql या jdbc का उपयोग किया जाता है या नहीं। जरूरत पड़ने पर आप अपना नकारात्मक संतुलन जांच सकते हैं। प्रदर्शन कोई मुद्दा नहीं होगा। वास्तविक समय शेष प्राप्त करने के लिए, यह एक सिंगलटन क्वेरी है।

संग्रह इस दृष्टिकोण को प्रभावित नहीं करेगा। रिपोर्ट जैसी चीजों के लिए जरूरत पड़ने पर आपके पास साप्ताहिक, मासिक, वार्षिक सारांश तालिका भी हो सकती है।


3

ओरेकल में आप ऐसा कर सकते हैं कि सिर्फ तेजी से रिफ्रेश किए जा सकने वाले मैटेरियलाइज्ड व्यू के साथ ट्रांजेक्शन टेबल का उपयोग करें जो बैलेंस बनाने के लिए एकत्रीकरण करता है। आप भौतिक दृश्य पर ट्रिगर को परिभाषित करते हैं। यदि भौतिक दृश्य को 'ON COMMIT' से परिभाषित किया जाता है, तो यह प्रभावी रूप से आधार तालिकाओं में डेटा को जोड़ने / संशोधित करने से रोकता है। ट्रिगर [] में वैध डेटा का पता लगाता है और एक अपवाद उठाता है, जहां यह लेनदेन को रोलबैक करता है। एक अच्छा उदाहरण यहाँ है http://www.sqlsnippets.com/en/topic-12896.html

मैं sqlserver नहीं जानता, लेकिन शायद यह एक समान विकल्प है?


2
Oracle में भौतिकीकृत दृश्य SQL सर्वर "अनुक्रमित दृश्य" के समान हैं, लेकिन वे Oracle के 'ON COMMIT' व्यवहार जैसे स्पष्ट रूप से प्रबंधित तरीके से स्वचालित रूप से ताज़ा होते हैं। देखें social.msdn.microsoft.com/Forums/fi-FI/transactsql/thread/... और techembassy.blogspot.com/2007/01/...
GregW
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.