Để trả lời đúng câu hỏi này, trước tiên bạn cần quyết định: "Xóa" nghĩa là gì trong ngữ cảnh của hệ thống / ứng dụng này?
Để trả lời câu hỏi đó , bạn cần trả lời một câu hỏi khác: Tại sao hồ sơ bị xóa?
Có một số lý do chính đáng tại sao người dùng có thể cần xóa dữ liệu. Thông thường tôi thấy rằng có chính xác một lý do (mỗi bảng) tại sao việc xóa có thể cần thiết. Một số ví dụ:
- Để lấy lại không gian đĩa;
- Xóa cứng cần thiết theo chính sách bảo mật / quyền riêng tư;
- Dữ liệu bị hỏng / vô vọng không chính xác, dễ xóa và tái tạo hơn là sửa chữa.
- Phần lớn các hàng bị xóa, ví dụ: bảng nhật ký giới hạn ở các bản ghi X / ngày.
Ngoài ra còn có một số lý do rất kém cho việc xóa cứng (thêm về lý do cho những điều này sau):
- Để sửa một lỗi nhỏ. Điều này thường nhấn mạnh sự lười biếng của nhà phát triển và giao diện người dùng thù địch.
- Để "hủy" một giao dịch (ví dụ: hóa đơn không bao giờ được lập hóa đơn).
- Bởi vì bạn có thể .
Tại sao, bạn hỏi, nó thực sự là một vấn đề lớn như vậy? Có chuyện gì với ole tốt DELETE
?
- Trong bất kỳ hệ thống nào thậm chí từ xa gắn liền với tiền, việc xóa cứng vi phạm tất cả các loại kỳ vọng kế toán, ngay cả khi được chuyển sang bảng lưu trữ / bia mộ. Cách chính xác để xử lý điều này là một sự kiện hồi tố .
- Các bảng lưu trữ có xu hướng phân kỳ khỏi lược đồ trực tiếp. Nếu bạn quên ngay cả một cột hoặc tầng mới được thêm vào, bạn đã mất dữ liệu đó vĩnh viễn.
- Xóa cứng có thể là một hoạt động rất tốn kém, đặc biệt là với các tầng . Rất nhiều người không nhận ra rằng xếp tầng nhiều hơn một cấp (hoặc trong một số trường hợp, bất kỳ tầng nào , tùy thuộc vào DBMS) sẽ dẫn đến các hoạt động ở mức kỷ lục thay vì các hoạt động được thiết lập.
- Lặp đi lặp lại, xóa cứng thường xuyên làm tăng tốc quá trình phân mảnh chỉ mục.
Vì vậy, xóa mềm là tốt hơn, phải không? Không thật sự lắm:
- Thiết lập thác trở nên vô cùng khó khăn. Bạn hầu như luôn luôn kết thúc với những gì xuất hiện cho khách hàng dưới dạng các hàng mồ côi.
- Bạn chỉ có thể theo dõi một lần xóa. Điều gì nếu hàng bị xóa và không bị xóa nhiều lần?
- Đọc hiệu suất bị ảnh hưởng, mặc dù điều này có thể được giảm nhẹ phần nào với phân vùng, khung nhìn và / hoặc các chỉ mục được lọc.
- Như được gợi ý trước đó, nó thực sự có thể là bất hợp pháp trong một số tình huống / khu vực pháp lý.
Sự thật là cả hai cách tiếp cận này đều sai. Xóa là sai. Nếu bạn thực sự hỏi câu hỏi này thì có nghĩa là bạn đang lập mô hình trạng thái hiện tại thay vì các giao dịch. Đây là một thực tiễn xấu, xấu trong cơ sở dữ liệu-đất đai.
Udi Dahan đã viết về điều này trong Không xóa - Chỉ cần đừng . Có luôn một số loại công việc, giao dịch, hoạt động , hoặc (ưu tiên hạn của tôi) sự kiện đó thực sự đại diện cho "delete". Sẽ ổn nếu sau đó bạn muốn chuẩn hóa thành bảng "trạng thái hiện tại" để thực hiện, nhưng hãy làm điều đó sau khi bạn đóng đinh mô hình giao dịch, chứ không phải trước đó.
Trong trường hợp này, bạn có "người dùng". Người dùng thực chất là khách hàng. Khách hàng có mối quan hệ kinh doanh với bạn. Mối quan hệ đó không chỉ đơn giản tan biến trong không khí mỏng manh vì họ đã hủy tài khoản của họ. Điều thực sự xảy ra là:
- Khách hàng tạo tài khoản
- Khách hàng hủy tài khoản
- Khách hàng gia hạn tài khoản
- Khách hàng hủy tài khoản
- ...
Trong mọi trường hợp, đó là cùng một khách hàng và có thể là cùng một tài khoản (tức là mỗi lần gia hạn tài khoản là một thỏa thuận dịch vụ mới). Vậy tại sao bạn lại xóa hàng? Đây là mô hình rất dễ dàng:
+-----------+ +-------------+ +-----------------+
| Account | --->* | Agreement | --->* | AgreementStatus |
+-----------+ +-------------+ +----------------+
| Id | | Id | | AgreementId |
| Name | | AccountId | | EffectiveDate |
| Email | | ... | | StatusCode |
+-----------+ +-------------+ +-----------------+
Đó là nó. Thats tất cả để có nó. Bạn không bao giờ cần phải xóa bất cứ điều gì. Trên đây là một thiết kế khá phổ biến có khả năng linh hoạt tốt nhưng bạn có thể đơn giản hóa nó một chút; bạn có thể quyết định rằng bạn không cần cấp độ "Thỏa thuận" và chỉ cần có "Tài khoản" vào bảng "AccountStatus".
Nếu một nhu cầu thường xuyên trong ứng dụng của bạn là có được một danh sách các thỏa thuận / tài khoản đang hoạt động thì đó là một truy vấn khó (hơi), nhưng đó là những lượt xem dành cho:
CREATE VIEW ActiveAgreements AS
SELECT agg.Id, agg.AccountId, acc.Name, acc.Email, s.EffectiveDate, ...
FROM AgreementStatus s
INNER JOIN Agreement agg
ON agg.Id = s.AgreementId
INNER JOIN Account acc
ON acc.Id = agg.AccountId
WHERE s.StatusCode = 'ACTIVE'
AND NOT EXISTS
(
SELECT 1
FROM AgreementStatus so
WHERE so.AgreementId = s.AgreementId
AND so.EffectiveDate > s.EffectiveDate
)
Và bạn đã hoàn thành. Bây giờ bạn có một cái gì đó với tất cả các lợi ích của xóa mềm nhưng không có nhược điểm nào:
- Hồ sơ mồ côi là một vấn đề không phải là vì tất cả các hồ sơ có thể nhìn thấy mọi lúc; bạn chỉ cần chọn từ một góc nhìn khác bất cứ khi nào cần thiết.
- "Xóa" thường là một hoạt động cực kỳ rẻ - chỉ cần chèn một hàng vào bảng sự kiện.
- Không bao giờ có bất kỳ cơ hội để mất bất kỳ lịch sử, bao giờ , cho dù bạn làm hỏng việc như thế nào.
- Bạn vẫn có thể xóa tài khoản nếu cần (ví dụ vì lý do riêng tư) và thoải mái với kiến thức rằng việc xóa sẽ diễn ra sạch sẽ và không can thiệp vào bất kỳ phần nào khác của ứng dụng / cơ sở dữ liệu.
Vấn đề duy nhất còn lại để giải quyết là vấn đề hiệu suất. Trong nhiều trường hợp, nó thực sự không thành vấn đề vì chỉ số được nhóm lại AgreementStatus (AgreementId, EffectiveDate)
- có rất ít I / O đang tìm kiếm ở đó. Nhưng nếu nó là một vấn đề, có nhiều cách để giải quyết vấn đề đó, bằng cách sử dụng các kích hoạt, các khung nhìn được lập chỉ mục / cụ thể hóa, các sự kiện ở cấp ứng dụng, v.v.
Đừng lo lắng về hiệu suất quá sớm - điều quan trọng hơn là phải thiết kế đúng và "đúng" trong trường hợp này có nghĩa là sử dụng cơ sở dữ liệu theo cách sử dụng cơ sở dữ liệu, như một hệ thống giao dịch .