Viết một lược đồ ngân hàng đơn giản: Làm thế nào tôi nên giữ số dư của mình đồng bộ với lịch sử giao dịch của họ?


57

Tôi đang viết lược đồ cho một cơ sở dữ liệu ngân hàng đơn giản. Dưới đây là các thông số kỹ thuật cơ bản:

  • Cơ sở dữ liệu sẽ lưu trữ các giao dịch chống lại người dùng và tiền tệ.
  • Mỗi người dùng có một số dư trên mỗi loại tiền, vì vậy mỗi số dư chỉ đơn giản là tổng của tất cả các giao dịch so với một người dùng và loại tiền nhất định.
  • Một số dư không thể âm.

Ứng dụng ngân hàng sẽ liên lạc với cơ sở dữ liệu của mình thông qua các thủ tục được lưu trữ.

Tôi hy vọng cơ sở dữ liệu này chấp nhận hàng trăm ngàn giao dịch mới mỗi ngày, cũng như các truy vấn cân bằng ở mức độ cao hơn. Để phục vụ số dư rất nhanh, tôi cần tổng hợp chúng trước. Đồng thời, tôi cần đảm bảo rằng số dư không bao giờ mâu thuẫn với lịch sử giao dịch của nó.

Lựa chọn của tôi là:

  1. Có một balancesbảng riêng và thực hiện một trong những điều sau đây:

    1. Áp dụng giao dịch cho cả bảng transactionsbalances. Sử dụng TRANSACTIONlogic trong lớp thủ tục được lưu trữ của tôi để đảm bảo rằng số dư và giao dịch luôn đồng bộ. (Được hỗ trợ bởi Jack .)

    2. Áp dụng các giao dịch vào transactionsbảng và có một trình kích hoạt cập nhật balancesbảng cho tôi với số tiền giao dịch.

    3. Áp dụng các giao dịch vào balancesbảng và có một trình kích hoạt thêm một mục mới trong transactionsbảng cho tôi với số tiền giao dịch.

    Tôi phải dựa vào các phương pháp dựa trên bảo mật để đảm bảo không có thay đổi nào có thể được thực hiện ngoài các thủ tục được lưu trữ. Mặt khác, ví dụ, một số quy trình có thể chèn trực tiếp một giao dịch vào transactionsbảng và theo sơ đồ 1.3, số dư có liên quan sẽ không đồng bộ.

  2. Có một balancescái nhìn được lập chỉ mục tổng hợp các giao dịch một cách thích hợp. Số dư được đảm bảo bởi công cụ lưu trữ để đồng bộ với các giao dịch của họ, vì vậy tôi không cần phải dựa vào các phương pháp dựa trên bảo mật để đảm bảo điều này. Mặt khác, tôi không thể thực thi số dư là không âm nữa vì các chế độ xem - ngay cả các chế độ xem được lập chỉ mục - không thể có các CHECKràng buộc. (Được hỗ trợ bởi Denny .)

  3. Chỉ có một transactionsbảng nhưng có một cột bổ sung để lưu trữ số dư có hiệu lực ngay sau khi giao dịch đó được thực hiện. Do đó, hồ sơ giao dịch mới nhất cho người dùng và tiền tệ cũng chứa số dư hiện tại của họ. (Được đề xuất dưới đây bởi Andrew ; biến thể được đề xuất bởi garik .)

Khi tôi lần đầu tiên giải quyết vấn đề này, tôi đọc những hai cuộc thảo luận và quyết định lựa chọn 2. Để tham khảo, bạn có thể thấy một triển khai xương cốt của nó ở đây .

  • Bạn đã thiết kế hoặc quản lý một cơ sở dữ liệu như thế này với cấu hình tải cao chưa? Giải pháp của bạn cho vấn đề này là gì?

  • Bạn có nghĩ rằng tôi đã lựa chọn thiết kế đúng? Có điều gì tôi nên ghi nhớ?

    Ví dụ, tôi biết các thay đổi lược đồ cho transactionsbảng sẽ yêu cầu tôi xây dựng lại balanceskhung nhìn. Ngay cả khi tôi đang lưu trữ các giao dịch để giữ cho cơ sở dữ liệu nhỏ (ví dụ: bằng cách di chuyển chúng sang nơi khác và thay thế chúng bằng các giao dịch tóm tắt), việc phải xây dựng lại chế độ xem hàng chục triệu giao dịch với mỗi bản cập nhật lược đồ có thể có nghĩa là thời gian ngừng hoạt động nhiều hơn đáng kể.

  • Nếu chế độ xem được lập chỉ mục là con đường để đi, làm thế nào tôi có thể đảm bảo rằng không có số dư nào là âm?


Giao dịch lưu trữ:

Hãy để tôi giải thích một chút về lưu trữ các giao dịch và "giao dịch tóm tắt" mà tôi đã đề cập ở trên. Đầu tiên, lưu trữ thường xuyên sẽ là một điều cần thiết trong một hệ thống tải cao như thế này. Tôi muốn duy trì tính nhất quán giữa số dư và lịch sử giao dịch của họ trong khi cho phép các giao dịch cũ được chuyển đi nơi khác. Để làm điều này, tôi sẽ thay thế mọi lô giao dịch được lưu trữ bằng một bản tóm tắt số tiền của mỗi người dùng và tiền tệ.

Vì vậy, ví dụ, danh sách các giao dịch này:

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

được lưu trữ và thay thế bằng cái này:

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

Theo cách này, số dư với các giao dịch lưu trữ duy trì một lịch sử giao dịch đầy đủ và nhất quán.


1
Nếu bạn chọn tùy chọn 2 (mà tôi nghĩ là sạch hơn), hãy xem pgcon.org/2008/schedule/attachments/ trên cách thực hiện "quan điểm cụ thể hóa" một cách hiệu quả. Đối với tùy chọn 1, chương 11 của Toán học ứng dụng cho các chuyên gia cơ sở dữ liệu của Haan và Koppelaars (đừng lo lắng về tiêu đề) sẽ hữu ích để có ý tưởng về cách thực hiện "các ràng buộc chuyển đổi" một cách hiệu quả. Liên kết đầu tiên là dành cho PostgreSQL và liên kết thứ hai cho Oracle, nhưng các kỹ thuật nên hoạt động cho bất kỳ hệ thống cơ sở dữ liệu hợp lý nào.
jp

Theo lý thuyết bạn muốn làm # 3. Cách chính xác để thực hiện "số dư hoạt động" là gán số dư cho mỗi giao dịch. Hãy chắc chắn rằng bạn có thể đặt hàng các giao dịch dứt khoát bằng ID nối tiếp (ưu tiên) hoặc dấu thời gian. Bạn thực sự không cần phải "tính toán" số dư đang chạy.
poustitenbach

Câu trả lời:


15

Tôi không quen thuộc với kế toán, nhưng tôi đã giải quyết một số vấn đề tương tự trong môi trường loại hàng tồn kho. Tôi lưu trữ tổng số chạy trong cùng một hàng với giao dịch. Tôi đang sử dụng các ràng buộc, để dữ liệu của tôi không bao giờ sai ngay cả dưới sự đồng thời cao. Tôi đã viết giải pháp sau đây vào năm 2009 ::

Tính toán tổng số chạy là rất chậm, cho dù bạn làm điều đó với một con trỏ hoặc với một phép nối tam giác. Sẽ rất hấp dẫn khi không chuẩn hóa, để lưu trữ tổng số đang chạy trong một cột, đặc biệt nếu bạn chọn nó thường xuyên. Tuy nhiên, như thường lệ khi bạn không chuẩn hóa, bạn cần đảm bảo tính toàn vẹn của dữ liệu không chuẩn hóa của bạn. May mắn thay, bạn có thể đảm bảo tính toàn vẹn của tổng số chạy với các ràng buộc - miễn là tất cả các ràng buộc của bạn được tin cậy, tất cả các tổng số chạy của bạn là chính xác. Ngoài ra, theo cách này, bạn có thể dễ dàng đảm bảo rằng số dư hiện tại (chạy tổng số) không bao giờ âm - việc thực thi bằng các phương pháp khác cũng có thể rất chậm. Các kịch bản sau đây thể hiện kỹ thuật.

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

Không cho phép khách hàng có số dư dưới 0 là một quy tắc kinh doanh (điều này sẽ thay đổi nhanh chóng vì phí cho những thứ như dự thảo là cách các ngân hàng kiếm phần lớn tiền của họ). Bạn sẽ muốn xử lý việc này trong xử lý ứng dụng khi các hàng được chèn vào lịch sử giao dịch. Đặc biệt là khi bạn có thể kết thúc với một số khách hàng có bảo vệ thấu chi và một số bị tính phí và một số không cho phép nhập số tiền âm.

Cho đến nay tôi thích nơi bạn sẽ đến với điều này, nhưng nếu đây là một dự án thực tế (không phải trường học) thì cần phải có rất nhiều suy nghĩ được đưa vào các quy tắc kinh doanh, v.v. Khi bạn đã có một hệ thống ngân hàng và hoạt động không có nhiều chỗ để thiết kế lại vì có những luật rất cụ thể về những người có quyền truy cập vào tiền của họ.


1
Tôi có thể thấy lý do tại sao các ràng buộc số dư thực sự nên là một quy tắc kinh doanh. Cơ sở dữ liệu chỉ cung cấp một dịch vụ giao dịch và tùy thuộc vào người dùng quyết định phải làm gì với nó.
Nick Chammas

Bạn nghĩ gì về nhận xét của Jack rằng việc sử dụng hai bảng giúp nhà phát triển linh hoạt hơn trong việc thay đổi hoặc triển khai logic kinh doanh? Ngoài ra, bạn có bất kỳ kinh nghiệm trực tiếp nào với các quan điểm được lập chỉ mục xác nhận hoặc thách thức những mối quan tâm này không?
Nick Chammas

1
Tôi sẽ không nói rằng có hai bảng cung cấp cho bạn sự linh hoạt di chuyển đang thực hiện logic kinh doanh. Nó giúp bạn linh hoạt hơn trong việc lưu trữ dữ liệu. Tuy nhiên, với tư cách là một ngân hàng (ít nhất là ở Hoa Kỳ), bạn đã có luật cho biết bạn cần giữ bao nhiêu dữ liệu. Bạn sẽ muốn kiểm tra hiệu suất trông như thế nào với chế độ xem ở trên cùng, cũng như tính đến việc nếu bạn có chế độ xem được lập chỉ mục, bạn không thể thay đổi lược đồ của các bảng bên dưới. Chỉ là một điều khác để suy nghĩ.
mrdenny

Tất cả các mục được đề cập trong bài viết là mối quan tâm hợp lệ đối với điều khi sử dụng chế độ xem được lập chỉ mục.
mrdenny

1
Để làm rõ: IMO một API giao dịch giúp triển khai logic kinh doanh linh hoạt hơn (không có hai bảng). Trong trường hợp này, tôi cũng sẽ ủng hộ hai bảng (ít nhất là đã cung cấp thông tin chúng tôi có từ trước đến nay) vì sự đánh đổi được đề xuất với phương pháp xem được lập chỉ mục (ví dụ: không thể sử dụng DRI để thực thi số dư> 0 doanh nghiệp quy tắc)
Jack Douglas

13

Một cách tiếp cận hơi khác (tương tự như tùy chọn thứ 2 của bạn ) cần xem xét là chỉ có bảng giao dịch, với định nghĩa:

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

Bạn cũng có thể muốn ID / Đơn hàng giao dịch, để bạn có thể xử lý hai giao dịch có cùng ngày và cải thiện truy vấn truy xuất của bạn.

Để có được số dư hiện tại, tất cả những gì bạn cần nhận là bản ghi cuối cùng.

Các phương pháp để có được bản ghi cuối cùng :

/* 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

Nhược điểm:

  • Khi chèn một giao dịch ra khỏi chuỗi (nghĩa là: để sửa một vấn đề / số dư bắt đầu không chính xác), bạn có thể cần xếp tầng cập nhật cho tất cả các giao dịch tiếp theo.
  • Các giao dịch cho Người dùng / Tiền tệ sẽ cần được tuần tự hóa để duy trì số dư chính xác.

    -- 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;

Ưu điểm:

  • Bạn không còn phải duy trì hai bảng riêng biệt ...
  • Bạn có thể dễ dàng xác thực số dư và khi số dư không đồng bộ, bạn có thể xác định chính xác khi nào hết tiền khi lịch sử giao dịch trở thành tài liệu tự ghi.

Chỉnh sửa: Một số truy vấn mẫu khi truy xuất số dư hiện tại và để làm nổi bật con (Cảm ơn @Jack Douglas)


3
Các SELECT TOP (1) ... ORDER BY TransactionDate DESCsẽ rất khó khăn để thực hiện theo cách như vậy mà SQL Server không liên tục quét các bảng giao dịch. Alex Kuznetsov đã đăng một giải pháp ở đây cho một vấn đề thiết kế tương tự hoàn toàn bổ sung cho câu trả lời này.
Nick Chammas

2
+1 Tôi đang sử dụng một cách tiếp cận tương tự. BTW, chúng tôi cần phải rất cẩn thận và đảm bảo mã của chúng tôi hoạt động chính xác theo khối lượng công việc đồng thời.
AK

12

Sau khi đọc hai cuộc thảo luận này, tôi quyết định lựa chọn 2

Đọc xong các cuộc thảo luận đó, tôi không chắc tại sao bạn lại quyết định giải pháp DRI theo cách hợp lý nhất trong số các lựa chọn khác mà bạn phác thảo:

Áp dụng giao dịch cho cả bảng giao dịch và số dư. Sử dụng logic GIAO DỊCH trong lớp thủ tục được lưu trữ của tôi để đảm bảo rằng số dư và giao dịch luôn đồng bộ.

Loại giải pháp này có lợi ích thiết thực to lớn nếu bạn có thể hạn chế tất cả quyền truy cập vào dữ liệu thông qua API giao dịch của mình. Bạn mất đi lợi ích rất quan trọng của DRI, đó là tính toàn vẹn được đảm bảo bởi cơ sở dữ liệu, nhưng trong bất kỳ mô hình nào đủ độ phức tạp sẽ có một số quy tắc kinh doanh không thể được thi hành bởi DRI .

Tôi khuyên bạn nên sử dụng DRI khi có thể để thực thi các quy tắc kinh doanh mà không làm cong mô hình của bạn quá nhiều để có thể thực hiện điều đó:

Ngay cả khi tôi đang lưu trữ các giao dịch (ví dụ: bằng cách di chuyển chúng sang nơi khác và thay thế chúng bằng các giao dịch tóm tắt)

Ngay khi bạn bắt đầu xem xét việc gây ô nhiễm mô hình của mình như thế này, tôi nghĩ rằng bạn đang tiến vào khu vực mà lợi ích của DRI lớn hơn những khó khăn mà bạn đang giới thiệu. Ví dụ, xem xét rằng một lỗi trong quy trình lưu trữ của bạn về lý thuyết có thể khiến quy tắc vàng của bạn (số dư đó luôn bằng tổng số giao dịch) phá vỡ âm thầm với giải pháp DRI .

Dưới đây là tóm tắt về những lợi thế của phương pháp giao dịch như tôi thấy chúng:

  • Chúng ta nên làm điều này bằng mọi cách nếu có thể. Bất cứ giải pháp nào bạn chọn cho vấn đề cụ thể này, nó sẽ giúp bạn linh hoạt hơn trong thiết kế và kiểm soát dữ liệu của mình. Tất cả các truy cập sau đó trở thành "giao dịch" về mặt logic kinh doanh, thay vì chỉ theo logic cơ sở dữ liệu.
  • Bạn có thể giữ mô hình của bạn gọn gàng
  • Bạn có thể "thực thi" phạm vi rộng hơn và phức tạp hơn của các quy tắc kinh doanh (lưu ý rằng khái niệm "thực thi" là một quy tắc lỏng lẻo hơn so với DRI)
  • Bạn vẫn có thể sử dụng DRI bất cứ nơi nào thiết thực để cung cấp cho mô hình tính toàn vẹn cơ bản mạnh mẽ hơn - và điều này có thể đóng vai trò kiểm tra logic giao dịch của bạn
  • Hầu hết các vấn đề về hiệu suất đang gây phiền toái bạn sẽ làm tan biến
  • Đưa ra các yêu cầu mới có thể dễ dàng hơn nhiều - ví dụ: các quy tắc phức tạp cho các giao dịch đang tranh chấp có thể buộc bạn tránh xa cách tiếp cận DRI thuần túy hơn nữa, có nghĩa là rất nhiều nỗ lực lãng phí
  • Phân vùng hoặc lưu trữ dữ liệu lịch sử trở nên ít rủi ro và đau đớn hơn nhiều

--biên tập

Để cho phép lưu trữ mà không cần thêm độ phức tạp hoặc rủi ro, bạn có thể chọn giữ các hàng tóm tắt trong một bảng tóm tắt riêng biệt, được tạo liên tục (mượn từ @Andrew và @Garik)

Ví dụ: nếu các bản tóm tắt là hàng tháng:

  • mỗi lần có một giao dịch (thông qua API của bạn) sẽ có một bản cập nhật tương ứng hoặc chèn vào bảng tóm tắt
  • bảng tóm tắt không bao giờ được lưu trữ, nhưng lưu trữ các giao dịch trở nên đơn giản như xóa aa (hoặc thả phân vùng?)
  • mỗi hàng trong bảng tóm tắt bao gồm 'số dư mở' và 'số tiền'
  • kiểm tra các ràng buộc như 'số dư mở' + 'số tiền'> 0 và 'số dư mở'> 0 có thể được áp dụng cho bảng tóm tắt
  • các hàng tóm tắt có thể được chèn vào một đợt hàng tháng để giúp khóa hàng tóm tắt mới nhất dễ dàng hơn (sẽ luôn có một hàng cho tháng hiện tại)

Về chỉnh sửa của bạn: Vì vậy, bạn đề xuất có bảng tóm tắt này cùng với bảng cân đối chính? Bảng cân đối sau đó có hiệu quả trở thành một bảng tóm tắt chỉ có các bản ghi cho tháng hiện tại (vì cả hai sẽ lưu trữ cùng một loại dữ liệu)? Nếu tôi đã hiểu chính xác, thì tại sao không chỉ thay thế bảng cân bằng bằng phân vùng thích hợp trên bảng tóm tắt?
Nick Chammas

Xin lỗi, bạn nói đúng là không rõ ràng - Tôi có nghĩa là bỏ qua bảng cân đối vì nó sẽ luôn là một tra cứu quan trọng trên bảng tóm tắt để có được số dư hiện tại (không đúng với đề xuất của AFAIK của Andrew). Ưu điểm là việc tính toán số dư ở những lần trước trở nên dễ dàng hơn và có một lộ trình kiểm toán rõ ràng hơn cho số dư nếu chúng đi sai.
Jack Douglas

6

Nick.

Ý tưởng chính là lưu trữ số dư và hồ sơ giao dịch trong cùng một bảng. Nó đã xảy ra trong lịch sử tôi nghĩ. Vì vậy, trong trường hợp này, chúng ta có thể lấy số dư chỉ bằng cách định vị bản ghi tóm tắt cuối cùng.

 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 

Một biến thể tốt hơn là giảm số lượng hồ sơ tóm tắt. Chúng tôi có thể có một bản ghi số dư vào cuối (và / hoặc bắt đầu) trong ngày. Như bạn đã biết, mọi ngân hàng đều operational dayphải mở và đóng cửa để thực hiện một số hoạt động tóm tắt cho ngày này. Nó cho phép chúng tôi dễ dàng tính lãi bằng cách sử dụng hồ sơ số dư mỗi ngày, ví dụ:

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)

May mắn


4

Dựa trên yêu cầu của bạn, tùy chọn 1 sẽ xuất hiện tốt nhất. Mặc dù tôi sẽ có thiết kế của mình chỉ cho phép chèn vào bảng giao dịch. Và có kích hoạt trên bảng giao dịch, để cập nhật bảng cân đối thời gian thực. Bạn có thể sử dụng quyền cơ sở dữ liệu để kiểm soát truy cập vào các bảng này.

Trong phương pháp này, số dư thời gian thực được đảm bảo đồng bộ với bảng giao dịch. Và nó không quan trọng nếu các thủ tục được lưu trữ hoặc psql hoặc jdbc được sử dụng. Bạn có thể kiểm tra số dư âm nếu cần. Hiệu suất sẽ không phải là một vấn đề. Để có được sự cân bằng thời gian thực, đó là một truy vấn đơn.

Lưu trữ sẽ không ảnh hưởng đến phương pháp này. Bạn cũng có thể có một bảng tóm tắt hàng tuần, hàng tháng, hàng năm nếu cần cho những thứ như báo cáo.


3

Trong Oracle, bạn có thể thực hiện việc này bằng cách chỉ sử dụng bảng giao dịch với Chế độ xem được Vật liệu hóa có thể làm mới nhanh trên đó thực hiện tổng hợp để tạo thành số dư. Bạn xác định kích hoạt trên Chế độ xem cụ thể hóa. Nếu Chế độ xem được vật chất hóa được xác định bằng 'ON CAMIT', thì nó có hiệu quả ngăn chặn việc thêm / sửa đổi dữ liệu trong các bảng cơ sở. Trình kích hoạt phát hiện dữ liệu hợp lệ [in] và đưa ra một ngoại lệ, trong đó nó khôi phục giao dịch. Một ví dụ điển hình là ở đây http://www.sqlsnippets.com/en/topic-12896.html

Tôi không biết sqlserver nhưng có lẽ nó có một tùy chọn tương tự?


2
Các khung nhìn được vật chất hóa trong Oracle tương tự như "khung nhìn được lập chỉ mục" của SQL Server, nhưng chúng tự động làm mới thay vì theo cách được quản lý rõ ràng, chẳng hạn như hành vi 'ON CAMIT' của Oracle. Xem social.msdn.microsoft.com/Forums/fi-FI/transactsql/thread/...techembassy.blogspot.com/2007/01/...
GregW
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.