Có phải là một thực tế xấu khi có một cột trạng thái bản ghi nhật ký trong một bảng cơ sở dữ liệu?


12

Trước tiên tôi phải làm rõ rằng cột trạng thái không nhằm phản ánh trạng thái của một mục trong thế giới thực được biểu thị bằng bản ghi (hàng) trong bảng. Thay vào đó, nó được dự định để hiển thị trạng thái của bản ghi.

Nó có thể đơn giản như Hoạt động / Không hoạt động hoặc phức tạp như Đã phê duyệt / Đã xóa / Đã khóa / Đang chờ / Từ chối, v.v. Trạng thái có thể được lưu trữ trên cột số nguyên boolean / ngắn hoặc cột một ký tự, với ánh xạ như true/ 1= Hoạt động hoặc A= Đã phê duyệt.

Ý tưởng cơ bản là có một thùng rác / hỗ trợ phục hồi giống như thùng rác trong ứng dụng (và mô phỏng nó trong cơ sở dữ liệu). Nếu có GUI phía trước hoặc giao diện khác có thể cho phép người dùng "xóa" các bản ghi, thì thực tế nó không xóa bản ghi trong bảng, mà chỉ thay đổi trạng thái bản ghi thành Không hoạt động hoặc Đã xóa. Khi giao diện tìm nạp các bản ghi, nó luôn nhận được các bản ghi chỉ phù hợp với điều kiện trạng thái là Hoạt động hoặc Được phê duyệt.

Nếu người dùng mắc lỗi và bản ghi "đã xóa" (theo quan điểm của người dùng) cần được phục hồi, DBA có thể dễ dàng vá lại bản ghi thành Đang hoạt động hoặc Được phê duyệt, sẽ tốt hơn tìm kiếm bản sao lưu và hy vọng tìm thấy bản ghi gốc ở đó Hoặc bản thân giao diện có thể cho phép người dùng xem các bản ghi bị xóa trong một chế độ xem riêng và khôi phục chúng khi cần hoặc thậm chí xóa chúng vĩnh viễn (xóa bản ghi thực tế).

Những câu hỏi của tôi:

  • Đây là một thực hành tốt, hay một thực hành xấu?
  • Nó có ảnh hưởng đến bình thường hóa dữ liệu?
  • Những cạm bẫy tiềm năng là gì?
  • Có phương pháp nào khác để đạt được cùng một mục tiêu không? (xem ghi chú)
  • Làm thế nào bạn có thể có cơ sở dữ liệu thực thi các ràng buộc duy nhất trên dữ liệu cho một trạng thái nhất định (nhưng cho phép bất kỳ số lượng trùng lặp cho các trạng thái khác)?
  • Tại sao cơ sở dữ liệu không cung cấp tính năng giống như "thùng rác" hoặc theo dõi / khôi phục bảng nguyên bản, vì vậy chúng tôi có thể để giao diện xóa các bản ghi thực mà không phải lo lắng?

Lưu ý: Tôi đã đọc về việc duy trì một bảng lịch sử riêng biệt nhưng điều đó có vẻ tệ hơn về mặt lưu trữ và phải tạo ra các kích hoạt và giữ cho các kích hoạt được cập nhật với lược đồ của bảng được theo dõi.


Vấn đề với các ràng buộc duy nhất (mà bạn đã đặt tên) chính xác là lý do tại sao các bảng lịch sử thường được ưa thích hơn - bạn có thể giữ các ràng buộc khóa duy nhất trên các bảng gốc và không thêm chúng vào bảng lịch sử. Ngoài ra, các bảng lịch sử riêng biệt cho phép dễ dàng hơn để sử dụng các tùy chọn lưu trữ cụ thể (phụ thuộc DB) cho chúng, vì vậy chúng thường tốt hơn về mặt lưu trữ, không tệ hơn. Khi bạn có nhiều bảng trong số đó, các bảng kích hoạt và lịch sử không nên được viết bằng tay mà được tạo ra, điều đó sẽ giải quyết vấn đề làm thế nào để giữ cho chúng "cập nhật".
Doc Brown

Câu trả lời:


5

Tôi biết điều này như là một "Xóa mềm"; chỉ đánh dấu một bản ghi là "đã xóa", mặc dù nó thực sự không.

Đây là một thực hành tốt, hay một thực hành xấu?

Nó phụ thuộc.
Nếu đây là thứ mà người dùng của bạn cần [rất nhiều] thì đó có lẽ là một điều tốt. Tuy nhiên, trong phần lớn các trường hợp, tôi sẽ lập luận rằng việc thêm [rất nhiều] chi phí cho ít lợi ích.

Nó có ảnh hưởng đến bình thường hóa dữ liệu?

Không, nhưng nó sẽ ảnh hưởng đến việc lập chỉ mục dữ liệu đó của bạn.
Đảm bảo rằng bạn bao gồm cột "đã xóa" trong các chỉ mục của mình để các hàng này bị loại trừ càng sớm càng tốt trong các truy vấn của bạn.

Những cạm bẫy tiềm năng là gì?

Dữ liệu của bạn trở nên phức tạp hơn một chút. Mọi thứ xuất hiện ở bất cứ đâu gần dữ liệu đều cần phải "biết" về các bản ghi bổ sung "không thực sự có" này. Hoặc, bạn phải tạo Chế độ xem trên các bảng loại trừ các hàng này và sử dụng các chế độ xem này, giả sử, Công cụ báo cáo lựa chọn của bạn.

Cơ sở dữ liệu của bạn có thể tăng kích thước. Nếu bạn không thực sự xóa các hàng này thì chúng vẫn ở đó, chiếm dung lượng. Điều này có thể hoặc không phải là một vấn đề, đặc biệt là vì bạn đã đưa chúng vào chỉ mục của mình, vì vậy không gian chúng tiêu thụ được nhân lên.

Có phương pháp nào khác để đạt được cùng một mục tiêu không? (xem ghi chú)

Không thực sự, không.

Làm thế nào bạn có thể có cơ sở dữ liệu thực thi các ràng buộc duy nhất trên dữ liệu cho một trạng thái nhất định (nhưng cho phép bất kỳ số lượng trùng lặp cho các trạng thái khác)?

Không dễ dàng. Tính toàn vẹn tham chiếu khai báo (mệnh đề khóa ngoài) là cách rõ ràng nhất để thực hiện điều này và thật dễ dàng cho những thứ như công cụ báo cáo chọn các quy tắc này để xác định mối quan hệ giữa các bảng. Các quy tắc như vậy áp dụng cho tất cả các hồ sơ, bất kể "trạng thái" (và không có cách nào khác).

Cách khác là sử dụng Triggers, đoạn mã thủ tục để thực thi tính toàn vẹn tham chiếu giữa các bảng và thực hiện tất cả các công cụ thông minh, có điều kiện mà bạn cần. Điều đó tốt cho trường hợp cụ thể của bạn, nhưng hầu hết các lợi ích của Tuyên bố RI đều vượt ra khỏi cửa sổ - không có mối quan hệ [bên ngoài] nào có thể phát hiện được giữa các bảng của bạn; đó là tất cả "ẩn" trong các kích hoạt.

Tại sao cơ sở dữ liệu không cung cấp tính năng giống như "thùng rác" hoặc theo dõi / khôi phục bảng nguyên bản, vì vậy chúng tôi có thể để giao diện xóa các bản ghi thực mà không phải lo lắng?

Tại sao sẽ họ?

Đây là những cơ sở dữ liệu, không phải là hệ thống tập tin hay bảng tính.

Những gì họ làm, họ [có thể] làm rất, rất tốt.

Những gì họ không làm, có lẽ không có nhiều nhu cầu cho.


Câu trả lời tốt, nhưng có các tùy chọn thay thế, ví dụ: di chuyển các hàng vào bảng sao lưu từ nơi bạn có thể khôi phục chúng. Bảng sao lưu có thể có các chỉ số tối thiểu. Điều này giảm thiểu các vấn đề bạn lưu ý với cách tiếp cận hiện có (chỉ mục lớn hơn, sự nhầm lẫn tiềm ẩn đối với người dùng bảng, v.v.), nhưng rõ ràng thêm một thực tế là bạn có một bảng khác để duy trì (và có nghĩa là các mục đã được chuyển sang tham chiếu khóa ngoài). Có khá nhiều tùy chọn khác - nhưng thực sự những lựa chọn mà bạn nghĩ đến đều là một số triển khai tùy chỉnh, không phải là thứ gì đó được cung cấp bởi mọi cơ sở dữ liệu SQL cho các trường hợp như vậy.
Frank Hopkins

9

Đó là một thực tế. Cho dù đó là tốt hay xấu phụ thuộc rất nhiều vào ứng dụng của bạn và mức độ phổ biến mà bạn thực sự sẽ cần / muốn thực hiện "không phục hồi". Tôi khá mơ hồ về một kế hoạch đặt loại cột đó của mỗi bảng trong hệ thống - có vẻ như rất khó để bạn thực sự bận tâm đến việc thực hiện không phục hồi trên mỗi bảng trong hệ thống. Và nó đòi hỏi phải thực hiện - trong phần lớn các trường hợp, bạn không hoàn tác một hàng từ một bảng duy nhất, bạn phải đi qua các bảng con xóa các hàng và cập nhật các bảng liên quan.

Đối với hầu hết các câu hỏi còn lại, nó phụ thuộc rất nhiều vào việc thực hiện. Ví dụ, Oracle cung cấp các phương pháp khác nhau để theo dõi tất cả các thay đổi đối với bảng-- Lưu trữ dữ liệu Flashback (FDA còn được gọi là Total Recall) là cách tiếp cận gần đây nhất để duy trì lịch sử đầy đủ của mọi phiên bản của một hàng và lưu trữ trong cơ sở dữ liệu để thực hiện mô hình xóa mềm. Các cơ sở dữ liệu khác có thể cung cấp các cách khác để thực hiện mẫu. Tùy thuộc vào cơ sở dữ liệu và cách bạn thực hiện xóa mềm, sẽ có nhiều tác động khác nhau đến hiệu suất, liệu các ràng buộc có thể được thi hành hay không, v.v. Nếu chúng ta đang nói về Oracle, bạn có thể làm rất nhiều với các chỉ mục dựa trên chức năng, ví dụ , trong SQL Server, bạn thường có thể sử dụng các chỉ mục được lọc cho các mục đích tương tự.


Oracle Flashback chính xác là giải pháp lý tưởng cho những gì tôi muốn. Quá tệ, đó là độc quyền của Oracle.
ADTC

4

Rất phổ biến để sử dụng trường "được gắn cờ để xóa" trong các hệ thống MRP / ERP.

Ví dụ, người ta có thể muốn đánh dấu một phần hoặc bản ghi hàng tồn kho không còn được bán là không hoạt động, nhưng vẫn có các đơn đặt hàng chưa xử lý được liên kết với nó. Việc xóa thực sự trong hồ sơ có thể ảnh hưởng đến các đơn hàng chưa được giao, các mục sổ cái chưa được đăng, các bảng lịch sử sẽ không được xây dựng cho đến cuối tháng, v.v. Nhiều hệ thống sẽ không cho phép xóa bản ghi trừ khi nó vượt qua một loạt xác nhận đối với các bảng khác. Nếu bạn đang xóa tầng trong các mối quan hệ của mình, việc xóa thực sự có thể còn phá hủy hơn nữa.

Thay vào đó, bằng cách đánh dấu nó để xóa, bạn đặt một dấu hiệu rõ ràng về ý định vào bản ghi và sau đó một tác vụ theo lịch trình có thể xóa bản ghi nếu nó xác minh rằng tất cả các bảng liên quan không còn tham chiếu đến nó nữa.

Một trường hợp tương tự có thể được thực hiện cho tính năng này trên bảng khách hàng và các bảng "dài hạn" khác. Nó thậm chí còn có ý nghĩa đối với các bảng dễ bay hơi hơn như đơn đặt hàng, mặc dù tên của cờ có thể trở thành một cái gì đó như "vận chuyển" hoặc "hủy bỏ". Nó phục vụ cùng một chức năng: không xóa nó lần thứ hai này, nhưng sử dụng nó làm cờ cho chương trình thanh lọc để nó cố gắng xác thực việc xóa bản ghi trong tương lai.


3

Là một giải pháp thay thế, việc sử dụng tìm nguồn cung cấp sự kiện cho phép các mục tiêu tương tự mà không làm phức tạp cấu trúc bảng, mặc dù nó làm cho mã sửa đổi dữ liệu của bạn phức tạp hơn một chút, vì bạn phải viết sửa đổi thành một sự kiện có thể được duy trì trong lịch sử sự kiện . Điều này sau đó cho phép bạn tạo lại cơ sở dữ liệu như tại bất kỳ thời điểm nào, đây có thể là một tính năng rất hữu ích.

(Tôi không tin đây là ý nghĩa của "bảng lịch sử", mà tôi nghĩ rằng bạn chỉ đơn giản là sao chép các bản ghi đã sửa đổi hoặc bị xóa vào một bảng khác trước khi thay đổi chúng)


Khái niệm thú vị. Tôi sẽ xem xét làm thế nào điều này có thể được thực hiện.
ADTC

1

Tôi thấy và sử dụng mẫu này thường xuyên cho các trường hợp sử dụng này:

  • siêu dữ liệu nơi bạn chỉ muốn hiển thị các giá trị có hiệu lực ngày hôm nay. Ví dụ: chọn từ danh sách các nhà sản xuất ô tô trong danh sách thả xuống trong đó bật = 1 các giá trị bảng cho ID, VALUE, ENABLED là 1, 'Ford', 1 và 2, 'Edsel', 0, 3, 'Toyota' , 1 chỉ cung cấp các lựa chọn của Ford và Toyota
  • đối với một hệ thống quản lý trường hợp trong đó mô hình là một trường hợp chỉ có thể ở một trạng thái tại một thời điểm. Trong trường hợp này, cột chuyển đổi được gọi là HIỆN TẠI với các giá trị 0 hoặc 1 được thi hành bởi các ràng buộc kiểm tra. Khi một trường hợp chuyển từ trạng thái này sang trạng thái khác, ứng dụng cập nhật cờ HIỆN TẠI của trạng thái cũ thành 0 và mới thành 1

Vấn đề là thực thi tính toàn vẹn dữ liệu nếu có nhiều hơn một ứng dụng hoặc dịch vụ web ghi vào bảng. Làm thế nào để bạn đảm bảo rằng trong một trường hợp chỉ có một trạng thái hiện tại? Như Justin Cave chỉ ra điều này có thể được thực hiện trong Oracle bằng cách tạo một chỉ mục ảo dựa trên một chức năng nhưng chi phí phụ này cho những gì ban đầu có vẻ là một khái niệm đơn giản.


1

Đó là một thực tiễn tốt nếu bạn có kế hoạch sử dụng dữ liệu của mình để báo cáo (bất kỳ ứng dụng nào đủ lớn sẽ cần phải có báo cáo).

Để tăng tốc ứng dụng của bạn, bạn thực sự không nên để các công cụ báo cáo chạy trên cơ sở dữ liệu của mình. Vì vậy, bạn cần phải sao chép / đồng bộ hóa với cơ sở dữ liệu khác.

Tôi chỉ sử dụng recordStatushai trạng thái ACTIVEhoặc CANCELLEDkết hợp với lastUpdatedOndấu thời gian. Tôi sử dụng recordStatuschứ không phải statusthường có ý nghĩa kinh doanh.

Khi tôi đồng bộ hóa cơ sở dữ liệu báo cáo với ứng dụng, tôi thực hiện một bộ lọc lastUpdatedOnđể biết những gì tôi sẽ thay thế ở phía báo cáo.

Về phía báo cáo tôi sẽ không có recordStatushoặc lastUpdatedOncác lĩnh vực vì nó thường sẽ không được báo cáo. Như vậy khi tôi thấy một CANCELLEDtrạng thái tôi sẽ xóa bản ghi khỏi phía báo cáo theo cách nó chỉ có các bản ghi hoạt động.

Điều này có thể được mở rộng sang các loại cửa hàng khác như lưu trữ hoặc sao lưu trong đó yêu cầu đồng bộ hóa gần như đầy đủ. Tuy nhiên, báo cáo là mục đích phổ biến hơn.

Chú ý Ví dụ bạn Approved, New, PendingKHÔNG phải là một ý tưởng tốt để đặt như một lĩnh vực phổ biến như rằng có một doanh nghiệp có nghĩa là nó nên đi chỉ đến nơi nó làm cho doanh nghiệp có ý nghĩa khôn ngoan.

Đối với khóa, sử dụng versionNocung cấp một khóa lạc quan cho hồ sơ của bạn.

Một lựa chọn khác thay vì recordStatusrecordActivevà nó được lưu trữ dưới dạng booleanchiếm ít không gian hơn và ít lập chỉ mục hơn, nhưng tôi sẽ lo ngại về các nhu cầu trong tương lai mà bạn có thể không thấy trước.

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.