Thứ Hai, 4 tháng 8, 2008

Cơ sở dữ liệu thời gian thực

Khi thiết kế CSDL, nhiều khi chúng ta gặp các đối tượng mà một số thông tin thường xuyên thay đổi theo thời gian. Lấy ví dụ, khi mô tả thông tin về nhân viên, thì ngoài các trường ít (hoặc không) thay đổi như Mã nhân viên, họ tên, số CMND… thì có một số trường có thể thay đổi như: Hệ số lương, chức danh, chức vụ. Trong một số trường hợp, các thông tin thay đổi thường xuyên, như tỉ giá ngoại tệ, giá bán sản phẩm…
Một trường hợp điển hình, đó là khi cần tính doanh thu của cửa hàng trong một tháng, khi đó giá của các sản phẩm (tính theo ngoại tệ) có sự thay đổi cũng như tỉ giá ngoại tệ có thể thay đổi theo từng ngày. Do đó, để tính doanh thu của tháng thì cần phải xác định giá của sản phẩm của từng ngày cũng như tỉ giá tương ứng, từ đó tính ra doanh thu ngày và tổng doanh thu của tháng.
Giải pháp thường được dùng là tạo một bảng diễn biến ứng với mỗi trường có thể thay đổi, và khi giá trị của trường thay đổi thì tạo một bản ghi mới. Tuy nhiên, cách này thường gây khó khăn trong việc tính toán, và khi có nhiều trường thay đổi thì cần phải tạo thêm rất nhiều bảng. Bài này đưa ra một mô hình cơ sở dữ liệu có khả năng lưu lại sự thay đổi của các trường.
Mô hình cơ sở dữ liệu theo thời gian
Để đáp ứng được khả năng lưu lại thay đổi theo thời gian, mỗi thông tin được lưu trữ trong CSDL theo 3 chiều, có nghĩa là để xác định được chính xác giá trị của trường chúng ta cần phải có các thông tin: Dòng, cột và thời gian.
Ví dụ, để liệt kê tỉ giá của ngoại tệ tại thời điểm 10:20 ngày 12/07/2007, chúng ta dùng câu lệnh:
SELECT Currency, Rate FROM ExchangeRateAt(’2007-8-12 10:20:00′)
Từ đó chúng ta sẽ xây dựng mô hình bảng dữ liệu với các đặc điểm sau:
Hỗ trợ đầy đủ các câu lệnh SELECT, INSERT, UPDATE, DELETE
Khi SELECT mà KHÔNG chỉ ra thời gian thì lấy giá trị của lần cập nhật gần đây nhất (giá trị hiện thời).
Khi SELECT mà CÓ chỉ ra thời gian, thì lấy các giá trị được cập nhật mới nhất tính đến thời điểm đó.
Khi SELECT tại một thời điểm, các bản ghi tạo ra sau thời điểm đó, hoặc bị xoá trước thời điểm đó sẽ không được đưa ra.
Khi INSERT một bản ghi mới, bản ghi sẽ tồn tại tính từ thời điểm thực hiện lệnh.
Khi UPDATE, giá trị mới của trường có tác dụng từ thời điểm thực hiện lệnh.
Khi DELETE, bản ghi bị xoá tính từ thời điểm thực hiện lệnh.
Với mô hình CSDL như trên, để tính doanh thu của các mặt hàng trong tháng khi giá mặt hàng thay đổi, thì câu truy vấn có thể đơn giản như sau:
SELECT SUM(Total) Total FROM(SELECT Transactions.Quantity*(SELECT Products.Price FROM ProductsAt(Transactions.Date) ProductsWHERE Products.ID = Transactions.ProductID) TotalFROM Transactions WHERE Transactions.Date BETWEEN @FromDate AND @ToDate) Transactions
Xây dựng bảng dữ liệu theo thời gian trên MS SQL Server
Các cơ sở dữ liệu quan hệ hiện nay không hỗ trợ chiều thời gian. Tuy nhiên, chúng ta có thể dùng hàm và view để thực hiện khả năng này.
Bảng lưu dữ liệu
Trước tiên, cần phải xây dựng bảng chứa dữ liệu chung cho tất cả các trường có thể thay đổi, bảng này có dạng như sau:

Trong đó các trường ItemID, RecordID, FieldIndex, Applied, Expired tương ứng với bảng, dòng, cột, thời điểm áp dụng và thời điểm bị xoá. Các trường còn lại tương ứng với kiểu dữ liệu của thông tin cần lưu trữ.
Để lấy ra một giá trị cụ thể của một trường thuộc một bản ghi tại một thời điểm nào đó, chúng ta xây dựng các hàm:
GetIntegerValue(@ItemID, @RecordID, @FieldIndex, @Time)
GetFloatValue(@ItemID, @RecordID, @FieldIndex, @Time)
GetDateTimeValue((@ItemID, @RecordID, @FieldIndex, @Time)
GetStringValue(@ItemID, @RecordID, @FieldIndex, @Time)
Chi tiết về các hàm này có thể xem trong CSDL minh hoạ đi kèm.
Tạo bảng dữ liệu theo thời gian bằng hàm inline và view
Để lấy dữ liệu tại một thời điểm nào đó, chúng ta xây dựng một hàm inline, ví dụ hàm sau lấy tỉ giá ngoại tệ tại một thời điểm:

Từ đó xây dựng một View tên là ExchageRate với dữ liệu tại thời điểm hiện thời.

View này hiện chưa có tính năng INSERT, UPDATE và DELETE, do đó chúng ta sẽ xây dựng các Trigger tương ứng cho phép cập nhật và xoá dữ liệu.
INSERT Trigger:

UPDATE Trigger

DELETE Trigger

Sử dụng bảng dữ liệu theo thời gian
Bảng dữ liệu theo thời gian (mà thực chất là hàm và view) được sử dụng bình thường như các bảng dữ liệu khác. Chúng ta có thể lấy dữ liệu tại thời điểm hiện thời hoặc tại một thời điểm nào đó, ví dụ như:
SELECT * FROM ExchangeRateAt(’12/6/2007 23:55:00′)SELECT * FROM ExchangeRate
Hoặc dùng các câu lênh cập nhật dữ liệu INSERT, UPDATE, DELETE, ví dụ:
INSERT ExchangeRate VALUES(N’HKD’, 8200)UPDATE ExchangeRate SET Rate = 16300 WHERE Currency = N’USD’DELETE ExchangeRate WHERE Currency = N’HKD’
Ưu điểm và hạn chế
Bảng dữ liệu theo thời gian thoả mãn đầy đủ những tính chất đã nêu ở trên, do đó có thể áp dụng vào các bài toán mà cần lưu lại sự thay đổi dữ liệu.
Do phải dùng hàm và view nên phương pháp này có một số hạn chế sau:
Không hỗ trợ ràng buộc dữ liệu: Do không phải là bảng thật nên không tạo được ràng buộc dữ liệu với các bảng khác.
Hiệu năng không cao: Do phải tính toán nhiều để đưa ra được kết quả nên không hiệu quả bằng truy vấn từ một bảng thật.
Phức tạp: Để tạo ra một bảng dữ liệu theo thời gian, cần phải xây dựng một hàm inline, một view và các trigger tương ứng. Tuy nhiên, cách xây dựng là như nhau cho các bảng.
Hướng mở rộng
Xây dựng các bảng dữ liệu lai giữa bảng thường (chứa các thông tin không cần lưu lại sự thay đổi) và các thông tin cần lưu lại sự thay đổi. Khi đó, các trường cần lưu lại sự thay đổi sẽ được thiết kế dưới dạng Computed Column và được cập nhật thông qua các trigger.

Không có nhận xét nào: