Yêu thích sự bất biến trong thiết kế cơ sở dữ liệu


26

Một trong những mục trong Java hiệu quả của Joshua Bloch là khái niệm rằng các lớp nên cho phép đột biến các cá thể càng ít càng tốt và tốt nhất là không nên.

Thông thường, dữ liệu của một đối tượng được lưu vào cơ sở dữ liệu dưới dạng nào đó. Điều này đã khiến tôi suy nghĩ về ý tưởng về tính bất biến trong cơ sở dữ liệu, đặc biệt là đối với những bảng đại diện cho một thực thể duy nhất trong một hệ thống lớn hơn.

Một cái gì đó tôi đã thử nghiệm gần đây là ý tưởng cố gắng giảm thiểu các bản cập nhật tôi làm cho các hàng bảng đại diện cho các đối tượng này và cố gắng thực hiện chèn thay vào đó nhiều nhất có thể.

Một ví dụ cụ thể về một cái gì đó tôi đã thử nghiệm gần đây. Nếu tôi biết tôi có thể nối thêm một bản ghi với dữ liệu bổ sung sau này, tôi sẽ tạo một bảng khác để thể hiện điều đó, giống như hai định nghĩa bảng sau:

create table myObj (id integer, ...other_data... not null);
create table myObjSuppliment (id integer, myObjId integer, ...more_data... not null);

Rõ ràng là những cái tên này không đúng nguyên văn, mà chỉ để thể hiện ý tưởng.

Đây có phải là một cách tiếp cận hợp lý để mô hình kiên trì dữ liệu? Có đáng để cố gắng hạn chế các cập nhật được thực hiện trên một bảng không, đặc biệt là điền vào null cho dữ liệu có thể không tồn tại khi bản ghi được tạo ban đầu? Có khi nào một cách tiếp cận như thế này có thể gây ra đau dữ dội về sau không?


7
Tôi cảm thấy đây là một giải pháp không có vấn đề gì ... Bạn nên cập nhật, thay vì tạo ra các điều chỉnh phức tạp để tránh cập nhật.
Fosco

Tôi nghĩ vấn đề là có một ý tưởng trực quan về một giải pháp trong đầu và muốn điều hành nó bởi càng nhiều người càng tốt, và trong quá trình nhận ra rằng đây có thể không phải là giải pháp tốt nhất cho vấn đề tôi gặp phải. Tôi có thể mở một câu hỏi khác với vấn đề, miễn là tôi không thể tìm thấy nó ở nơi khác.
Ed Carrel

1
Có thể có lý do chính đáng để tránh cập nhật trong cơ sở dữ liệu. Tuy nhiên, khi những lý do này xuất hiện, đó là vấn đề tối ưu hóa nhiều hơn và vì thế không nên thực hiện mà không có bằng chứng cho thấy có vấn đề.
dietbuddha

6
Tôi nghĩ rằng có một lập luận mạnh mẽ cho sự bất biến trong cơ sở dữ liệu. Nó giải quyết rất nhiều vấn đề. Tôi nghĩ rằng những bình luận tiêu cực không đến từ những người cởi mở. Cập nhật tại chỗ là nguyên nhân của rất nhiều vấn đề. Tôi sẽ tranh luận rằng chúng ta có tất cả lạc hậu. Cập nhật tại chỗ là giải pháp kế thừa cho một vấn đề không còn tồn tại. Lưu trữ là giá rẻ. Tại sao làm điều đó? Có bao nhiêu hệ thống DB có nhật ký kiểm toán, hệ thống phiên bản, cần nhân rộng phân tán mà như chúng ta đều biết đòi hỏi khả năng hỗ trợ độ trễ cho quy mô. Bất biến giải quyết tất cả điều này.
xơ gan

@Fosco Một số hệ thống hoàn toàn bắt buộc phải không bao giờ xóa dữ liệu (bao gồm cả việc sử dụng UPDATE). Giống như hồ sơ y tế của bác sĩ.
Izkata

Câu trả lời:


25

Mục đích chính của tính không thay đổi là để đảm bảo rằng không có thời gian tức thì khi dữ liệu trong bộ nhớ ở trạng thái không hợp lệ. (Khác là vì các ký hiệu toán học chủ yếu là tĩnh và vì vậy những thứ bất biến dễ dàng khái niệm hóa và mô hình hóa hơn về mặt toán học.) Trong bộ nhớ, nếu một luồng khác cố đọc hoặc ghi dữ liệu trong khi nó đang hoạt động, nó có thể bị hỏng, hoặc nó có thể tự nó ở trong tình trạng tham nhũng. Nếu bạn có nhiều thao tác gán cho các trường của đối tượng, trong một ứng dụng đa luồng, một luồng khác có thể cố gắng làm việc với nó đôi khi ở giữa - điều này có thể xấu.

Tính không thay đổi khắc phục điều này bằng cách trước tiên viết tất cả các thay đổi vào một vị trí mới trong bộ nhớ, và sau đó thực hiện nhiệm vụ cuối cùng là một bước viết lại của con trỏ tới đối tượng để trỏ đến đối tượng mới - mà trên tất cả các CPU là một nguyên tử hoạt động.

Cơ sở dữ liệu thực hiện điều tương tự bằng các giao dịch nguyên tử : khi bạn bắt đầu giao dịch, nó ghi tất cả các bản cập nhật mới vào một vị trí mới trên đĩa. Khi bạn hoàn thành giao dịch, nó sẽ thay đổi con trỏ trên đĩa thành nơi cập nhật mới - điều này sẽ diễn ra trong một thời gian ngắn trong khi các quá trình khác không thể chạm vào nó.

Đây cũng chính là điều tương tự như ý tưởng của bạn về việc tạo các bảng mới, ngoại trừ tự động hơn và linh hoạt hơn.

Vì vậy, để trả lời câu hỏi của bạn, vâng, tính bất biến là tốt trong cơ sở dữ liệu, nhưng không, bạn không cần phải tạo các bảng riêng biệt cho mục đích đó; bạn chỉ có thể sử dụng bất kỳ lệnh giao dịch nguyên tử nào có sẵn cho hệ thống cơ sở dữ liệu của bạn.


Cảm ơn câu trả lời. Viễn cảnh này chỉ là những gì tôi cần để nhận ra rằng trực giác của tôi đang cố gắng kết hợp một vài ý tưởng khác nhau thành một mô hình duy nhất.
Ed Carrel

8
Có nhiều hơn một chút so với đạn. Đối số tôi thấy thường xuyên nhất ủng hộ tính bất biến trong ngữ cảnh OOP là các đối tượng bất biến chỉ yêu cầu bạn xác thực trạng thái của chúng một lần, trong hàm tạo. Nếu chúng có thể thay đổi, thì mọi phương thức có thể thay đổi trạng thái của chúng cũng được yêu cầu để xác minh rằng trạng thái kết quả vẫn hợp lệ, điều này có thể thêm độ phức tạp đáng kể cho lớp. Đối số này cũng có khả năng áp dụng cho cơ sở dữ liệu, nhưng yếu hơn nhiều, vì các quy tắc xác thực db có xu hướng khai báo thay vì theo thủ tục, vì vậy chúng không cần phải được sao chép cho mọi truy vấn.
Dave Sherohman

24

Nó phụ thuộc vào những lợi ích bạn mong đợi để đạt được từ sự bất biến. Câu trả lời của Rei Miyasaka đã giải quyết một (tránh các trạng thái trung gian không hợp lệ), nhưng đây là một trạng thái khác.

Đột biến đôi khi được gọi là cập nhật phá hoại : khi bạn đột biến một đối tượng, trạng thái cũ sẽ bị mất (trừ khi bạn thực hiện các bước bổ sung để bảo toàn rõ ràng bằng cách nào đó). Ngược lại, với dữ liệu không thay đổi, việc đại diện đồng thời trạng thái cả trước và sau một số thao tác hoặc đại diện cho nhiều trạng thái kế tiếp là không quan trọng. Hãy tưởng tượng bạn đang cố gắng thực hiện tìm kiếm đầu tiên bằng cách thay đổi một đối tượng trạng thái duy nhất.

Điều này có lẽ xuất hiện trong thế giới cơ sở dữ liệu thường xuyên nhất là dữ liệu tạm thời . Giả sử tháng trước bạn đã sử dụng gói Cơ bản, nhưng vào ngày 16, bạn đã chuyển sang gói Premium. Nếu chúng tôi chỉ ghi đè lên một số lĩnh vực cho biết bạn đang lên kế hoạch gì, chúng tôi có thể gặp khó khăn trong việc thanh toán đúng. Chúng ta cũng có thể bỏ lỡ khả năng phân tích xu hướng. (Này, hãy xem những gì chiến dịch quảng cáo địa phương này đã làm!)

Dù sao đó cũng là điều tôi nghĩ đến khi bạn nói "bất biến trong thiết kế cơ sở dữ liệu".


2
Tôi không đồng ý với đoạn thứ ba của bạn. Nếu bạn muốn có một lịch sử (nhật ký kiểm toán, nhật ký thay đổi kế hoạch, v.v.), bạn phải tạo một bảng riêng cho việc này. Sao chép tất cả 50 trường của Customerbảng chỉ để nhớ rằng người dùng đã thay đổi gói không mang lại điều gì ngoại trừ nhược điểm hiệu suất lớn, chọn chậm hơn theo thời gian, khai thác dữ liệu phức tạp hơn (so với nhật ký) và lãng phí nhiều không gian hơn.
Arseni Mourzenko

6
@MainMa: có lẽ tôi nên nói "hãy đọc về cơ sở dữ liệu tạm thời". Ví dụ của tôi được dự định là một bản phác thảo về dữ liệu tạm thời là gì; Tôi không khẳng định đó luôn là cách tốt nhất để thể hiện dữ liệu thay đổi. Mặt khác, mặc dù hiện tại việc hỗ trợ dữ liệu tạm thời khá kém, tôi hy vọng xu hướng sẽ hướng tới việc cung cấp dữ liệu tạm thời trong cơ sở dữ liệu, thay vì đưa nó vào các biểu diễn "lớp thứ hai" như nhật ký thay đổi.
Ryan Culpepper

Điều gì sẽ xảy ra nếu chúng ta duy trì lịch sử thay đổi trong bảng kiểm toán (khởi động mùa xuân và ngủ đông chẳng hạn như tắt khả năng này)?
Mohammad Najar

14

Nếu bạn quan tâm đến lợi ích bạn có thể nhận được từ tính bất biến trong cơ sở dữ liệu hoặc ít nhất là cơ sở dữ liệu cung cấp ảo ảnh về tính bất biến, hãy kiểm tra Datomic.

Datomic là một Cơ sở dữ liệu được phát minh bởi Rich Hickey trong liên minh với Think Relevance, có rất nhiều video giải thích kiến ​​trúc, mục tiêu, mô hình dữ liệu. Tìm kiếm thông tin, một cụ thể có tiêu đề Datomic, Cơ sở dữ liệu như một giá trị . Trong các bản tin, bạn có thể tìm thấy một bài phát biểu mà Rich Hickey đã đưa ra tại hội nghị euroclojure năm 2012. confreaks.com/ideo/2077-euroclojure2012-day-2-keynote-the-datomic-arch architecture-and-data-model

Có một cuộc nói chuyện trong vimeo.com/53162418 được định hướng phát triển hơn.

Đây là một cái khác từ stuart halloway at.pscdn.net/008/00102/videopl platform/kv/121105techconf_close.html

  • Datomic là một cơ sở dữ liệu về các sự kiện trong thời gian, được gọi là datum, trong 5 tuples [E, A, V, T, O]
    • E Entity id
    • Một tên thuộc tính trong thực thể (có thể có không gian tên)
    • Giá trị V của thuộc tính
    • T ID giao dịch, với điều này bạn có khái niệm về thời gian.
    • O Một thao tác xác nhận (giá trị hiện tại hoặc hiện tại), từ chối (giá trị quá khứ);
  • Sử dụng định dạng dữ liệu của riêng nó, được gọi là EDN (Ký hiệu dữ liệu mở rộng)
  • Giao dịch là ACID
  • Sử dụng datalog làm ngôn ngữ truy vấn, wich là khai báo dưới dạng truy vấn đệ quy SQL +. Các truy vấn được biểu diễn với cấu trúc dữ liệu và được mở rộng bằng ngôn ngữ jvm của bạn, bạn không cần sử dụng clojure.
  • Cơ sở dữ liệu được tách rời trong 3 dịch vụ riêng biệt (quy trình, máy móc):
    • Giao dịch
    • Lưu trữ
    • Công cụ truy vấn.
  • Bạn có thể riêng biệt, quy mô từng dịch vụ.
  • Nó không phải là nguồn mở, nhưng có phiên bản miễn phí (như trong bia) của Datomic.
  • Bạn có thể nêu một lược đồ linh hoạt.
    • bộ thuộc tính đang mở
    • thêm thuộc tính mới bất cứ lúc nào
    • không có sự cứng nhắc trong định nghĩa hoặc truy vấn

Bây giờ, vì thông tin được lưu trữ dưới dạng sự kiện trong thời gian:

  • tất cả những gì bạn làm là thêm sự kiện vào cơ sở dữ liệu, bạn không bao giờ xóa chúng (trừ khi luật pháp yêu cầu)
  • bạn có thể lưu trữ mọi thứ mãi mãi Công cụ truy vấn, sống trong máy chủ ứng dụng dưới dạng cơ sở dữ liệu trong bộ nhớ (đối với các ngôn ngữ jvm, các ngôn ngữ không phải jvm có quyền truy cập thông qua API REST.)
  • bạn có thể truy vấn theo thời gian trong quá khứ.

Cơ sở dữ liệu là một giá trị và là một tham số cho công cụ truy vấn, QE quản lý kết nối và bộ đệm. Vì bạn có thể xem db là một giá trị và cấu trúc dữ liệu không thay đổi trong bộ nhớ, bạn có thể hợp nhất nó với một cấu trúc dữ liệu khác được tạo từ các giá trị "trong tương lai" và chuyển nó sang QE & truy vấn với các giá trị trong tương lai, mà không thay đổi cơ sở dữ liệu thực tế .

Có một dự án nguồn mở từ Rich Hickey, được gọi là codeq , bạn có thể tìm thấy nó trong github Datomic / codeq, mở rộng mô hình git và lưu trữ các tham chiếu đến các đối tượng git trong cơ sở dữ liệu không có dữ liệu và bạn thực hiện các truy vấn về mã của mình có thể xem một ví dụ về cách sử dụng datomic.

Bạn có thể nghĩ về datomic như một ACID NoQuery, với các datum bạn có thể mô hình hóa các bảng hoặc tài liệu hoặc Kv-store hoặc đồ thị.


7

Ý tưởng tránh cập nhật và thích chèn, là một trong những suy nghĩ đằng sau việc xây dựng bộ lưu trữ dữ liệu của bạn dưới dạng Nguồn sự kiện, một ý tưởng bạn sẽ thường thấy được sử dụng cùng với CQRS. Trong mô hình nguồn sự kiện, không có cập nhật: một tổng hợp được biểu diễn dưới dạng chuỗi "biến đổi" (sự kiện) của nó và kết quả là bộ lưu trữ chỉ được nối thêm.
Trang web này chứa các cuộc thảo luận thú vị về CQRS và tìm nguồn cung ứng sự kiện, nếu bạn tò mò về nó!


CQRS và tìm nguồn cung ứng sự kiện đang trở nên nổi bật trong những ngày này.
Gul Sơn

6

Điều này có mối quan hệ rất chặt chẽ với cái được gọi là "Kích thước thay đổi chậm" trong thế giới lưu trữ dữ liệu và các bảng "Tạm thời" hoặc "Bi-Temporal" trong các miền khác.

Cấu trúc cơ bản là:

  1. Luôn sử dụng khóa thay thế được tạo làm khóa chính.
  2. Mã định danh duy nhất của bất cứ điều gì bạn đang mô tả sẽ trở thành "khóa logic".
  3. Mỗi hàng nên có ít nhất một dấu thời gian "Hợp lệ" và tùy chọn dấu thời gian "Hợp lệ" và thậm chí nhiều tùy chọn hơn là cờ "Phiên bản mới nhất".
  4. Trên "tạo" của một thực thể logic, bạn Chèn một hàng mới với "Hợp lệ từ" của dấu thời gian hiện tại. Hợp lệ tùy chọn được đặt thành "mãi mãi" (9999-12-31 23:59:59) và Phiên bản cuối cùng thành "Đúng".
  5. Trên một bản cập nhật tiếp theo của thực thể logic. Bạn ít nhất chèn một hàng mới như trên. Bạn cũng có thể cần điều chỉnh Hợp lệ trên phiên bản trước thành "now () - 1 giây" và Phiên bản mới nhất thành "Sai"
    1. Khi xóa logic (điều này chỉ hoạt động với dấu thời gian hợp lệ!), Bạn đặt cờ Hợp lệ trong hàng hiện tại thành "now () -1 giây".

Ưu điểm của sơ đồ này là bạn có thể tạo lại "trạng thái" của thực thể logic của mình tại bất kỳ thời điểm nào, bạn có một lịch sử về thực thể của mình theo thời gian và bạn giảm thiểu sự tranh chấp nếu "thực thể logic" của bạn được sử dụng nhiều.

Nhược điểm là bạn lưu trữ nhiều dữ liệu hơn và bạn cần duy trì nhiều chỉ mục hơn (ít nhất là trên Khóa logic + ValidFrom + ValidTo). Một chỉ mục trên Khóa logic + Phiên bản mới nhất tăng tốc đáng kể hầu hết các truy vấn. Nó cũng làm phức tạp SQL của bạn!

Việc này có đáng làm hay không trừ khi bạn thực sự cần duy trì lịch sử và có yêu cầu tạo lại trạng thái của các thực thể tại một thời điểm nhất định tùy thuộc vào bạn.


1

Một lý do có thể khác để có một cơ sở dữ liệu bất biến là để hỗ trợ xử lý song song tốt hơn. Các cập nhật xảy ra ngoài trật tự có thể làm rối dữ liệu vĩnh viễn, do đó việc khóa phải xảy ra để ngăn chặn điều đó, phá hủy hiệu suất song song. Rất nhiều phần chèn của các sự kiện có thể đi theo bất kỳ thứ tự nào, và trạng thái ít nhất sẽ cuối cùng đúng miễn là tất cả các sự kiện cuối cùng được xử lý. Tuy nhiên, điều này rất khó để làm việc trong thực tế so với thực hiện cập nhật cơ sở dữ liệu mà bạn sẽ thực sự cần rất nhiều sự song song để xem xét thực hiện theo cách này - tôi không khuyến nghị điều đó.


0

Tuyên bố miễn trừ trách nhiệm: Tôi gần như là một người mới trong DB: p

Điều đó đang được nói, cách tiếp cận dữ liệu vệ tinh này có tác động ngay lập tức đến hiệu suất:

  • Tốt ít lưu lượng trên bảng chính
  • Hàng nhỏ tốt hơn trên bảng chính
  • Xấu yêu cầu dữ liệu vệ tinh có nghĩa là cần phải tra cứu
  • Không gian bị chiếm dụng nhiều hơn nếu tất cả các đối tượng tồn tại trong cả hai bảng

tùy thuộc vào yêu cầu của bạn, bạn có thể hoan nghênh điều này hoặc không, nhưng chắc chắn đây là một điểm cần xem xét.


-1

Tôi không thấy làm thế nào chương trình của bạn có thể được gọi là "bất biến".

Điều gì xảy ra khi một giá trị được lưu trữ trong bảng bổ sung thay đổi? Có vẻ như bạn sẽ cần phải thực hiện cập nhật trên bảng đó.

Để một cơ sở dữ liệu thực sự bất biến, nó sẽ chỉ cần được duy trì bởi "INSERTS". Đối với điều này, bạn cần một số phương pháp xác định hàng "hiện tại". Điều này gần như luôn luôn kết thúc là không hiệu quả khủng khiếp. Bạn phải sao chép tất cả các giá trị không thay đổi trước đó hoặc ghép lại trạng thái hiện tại từ một số bản ghi khi bạn truy vấn. Việc lựa chọn hàng hiện tại thường cần một số SQL lộn xộn khủng khiếp như ( where updTime = (SELECT max(updTime) from myTab where id = ?).

Vấn đề này xuất hiện rất nhiều trong DataWarehousing, nơi bạn cần lưu giữ lịch sử dữ liệu theo thời gian và có thể chọn trạng thái cho bất kỳ thời điểm nào. Các giải pháp thường là bảng "chiều". Tuy nhiên, trong khi họ giải quyết vấn đề DW "ai là đại diện bán hàng vào tháng 1 năm ngoái". Chúng không cung cấp bất kỳ lợi thế nào mà các lớp bất biến Javas làm được.

Trên một ghi chú triết học hơn; cơ sở dữ liệu tồn tại để lưu trữ "trạng thái" (số dư ngân hàng, mức tiêu thụ điện, điểm brownie của bạn trên StackOverflow, v.v.) cố gắng đưa ra cơ sở dữ liệu "không trạng thái" dường như là một bài tập khá vô nghĩa.


Đối với một bản ghi, WHERE id = {} ORDER BY updTime DESC LIMIT 1thường không quá kém hiệu quả.
Izkata

@Izkata - hãy thử đặt hte vào giữa ba bảng tham gia :-)
James Anderson
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.