Skenarionya adalah saya mendapatkan sekelompok pengguna yang terus bertambah, dan seiring berjalannya waktu, pengguna akan membatalkan akun mereka yang saat ini kami tandai sebagai 'dihapus' (dengan bendera) di tabel yang sama.
Jika pengguna dengan alamat email yang sama (itulah cara pengguna masuk) ingin membuat akun baru, mereka dapat mendaftar lagi, tetapi akun BARU dibuat. (Kami memiliki id unik untuk setiap akun, sehingga alamat email dapat digandakan di antara yang hidup dan yang dihapus).
Apa yang saya perhatikan adalah bahwa di seluruh sistem kami, dalam hal normal, kami terus-menerus meminta tabel pengguna memeriksa pengguna tidak dihapus, sedangkan yang saya pikirkan adalah bahwa kami tidak perlu melakukan itu sama sekali ... ! [Klarifikasi1: dengan 'terus-menerus menanyakan', maksud saya bahwa kami memiliki pertanyaan seperti: '... DARI pengguna DI MANA isdeleted = "0" AND ...'. Misalnya, kami mungkin perlu mengambil semua pengguna yang terdaftar untuk semua rapat pada tanggal tertentu, jadi dalam kueri ITU, kami juga memiliki DARI pengguna. DI MANA isdeleted = "0" - apakah ini membuat poin saya lebih jelas?]
(1) continue keeping deleted users in the 'main' users table
(2) keep deleted users in a separate table (mostly required for historical
book-keeping)
Apa pro dan kontra dari kedua pendekatan tersebut?
sumber
Jawaban:
Anda dapat menggunakan misalnya pemicu untuk memindahkan pengguna yang dihapus ke tabel riwayat secara otomatis.
sumber
Saya sangat merekomendasikan menggunakan tabel yang sama. Alasan utamanya adalah integritas data. Kemungkinan besar akan ada banyak tabel dengan hubungan tergantung pada pengguna. Ketika pengguna dihapus, Anda tidak ingin meninggalkan catatan itu menjadi yatim piatu.
Memiliki catatan yatim piatu membuat penegakan kendala lebih sulit, dan membuatnya lebih sulit untuk mencari informasi historis. Perilaku lain yang perlu dipertimbangkan jika ketika pengguna memasok email bekas jika Anda ingin mereka memulihkan semua catatan lama mereka. Ini akan bekerja secara otomatis dengan menggunakan penghapusan lunak. Sejauh pengkodean, misalnya dalam aplikasi c # linq saya saat ini di mana dihapus = 0 klausa secara otomatis ditambahkan ke akhir semua pertanyaan
sumber
Ini memberi saya bau desain. Anda harus menyembunyikan logika semacam itu. Misalnya, Anda harus
UserService
menyediakan metodeisValidUser(userId)
untuk digunakan "di seluruh sistem Anda", daripada melakukan sesuatu seperti:Cara Anda untuk menyimpan pengguna yang dihapus tidak boleh memengaruhi logika bisnis.
Dengan semacam enkapsulasi, argumen di atas seharusnya tidak lagi mempengaruhi pendekatan kegigihan Anda. Maka Anda bisa lebih fokus pada pro dan kontra yang terkait dengan kegigihan itu sendiri.
Hal-hal yang perlu dipertimbangkan termasuk:
Biasanya saya akan mengambil cara gabungan:
sumber
Untuk menjawab dengan benar pertanyaan ini, Anda harus terlebih dahulu memutuskan: Apa arti "hapus" dalam konteks sistem / aplikasi ini?
Untuk menjawab bahwa pertanyaan, Anda perlu menjawab pertanyaan lain: Mengapa yang catatan yang dihapus?
Ada sejumlah alasan bagus mengapa pengguna mungkin perlu menghapus data. Biasanya saya menemukan bahwa hanya ada satu alasan (per tabel) mengapa penghapusan mungkin diperlukan. Beberapa contoh adalah:
Ada juga beberapa alasan yang sangat buruk untuk penghapusan-keras (lebih lanjut tentang alasan untuk ini nanti):
Mengapa, Anda bertanya, apakah ini benar-benar masalah besar? Apa yang salah dengan ole bagus
DELETE
?Jadi, hapus lunak lebih baik, bukan? Tidak terlalu:
Yang benar adalah kedua pendekatan ini salah. Menghapus itu salah. Jika Anda benar-benar mengajukan pertanyaan ini maka itu berarti Anda memodelkan keadaan saat ini alih-alih transaksi. Ini adalah praktik buruk, buruk di basis data.
Udi Dahan menulis tentang ini di Don't Delete - Just Don't . Ada selalu semacam tugas, transaksi, aktivitas , atau (jangka pilihan saya) acara yang benar-benar mewakili "delete". Tidak apa-apa jika Anda kemudian ingin melakukan denormalisasi ke dalam tabel "kondisi saat ini" untuk kinerja, tetapi lakukan itu setelah Anda berhasil menyelesaikan model transaksional, bukan sebelumnya.
Dalam hal ini Anda memiliki "pengguna". Pengguna pada dasarnya adalah pelanggan. Pelanggan memiliki hubungan bisnis dengan Anda. Hubungan itu tidak hilang begitu saja karena mereka membatalkan akun mereka. Apa yang sebenarnya terjadi adalah:
Dalam setiap kasus, itu adalah pelanggan yang sama , dan mungkin akun yang sama (yaitu setiap pembaruan akun adalah perjanjian layanan baru). Jadi mengapa Anda menghapus baris? Ini sangat mudah untuk dimodelkan:
Itu dia. Itu semua yang ada untuk itu. Anda tidak perlu menghapus apa pun. Di atas adalah desain yang cukup umum yang mengakomodasi tingkat fleksibilitas yang baik tetapi Anda dapat menyederhanakannya sedikit; Anda mungkin memutuskan bahwa Anda tidak memerlukan level "Perjanjian" dan cukup "Account" masuk ke tabel "AccountStatus".
Jika sering dibutuhkan dalam aplikasi Anda untuk mendapatkan daftar perjanjian / akun aktif maka itu adalah (sedikit) permintaan rumit, tapi itulah gunanya tampilan:
Dan kamu sudah selesai. Sekarang Anda memiliki sesuatu dengan semua manfaat penghapusan-lunak tetapi tidak ada kekurangan:
Satu-satunya masalah yang tersisa untuk ditangani adalah masalah kinerja. Dalam banyak kasus itu ternyata bukan masalah karena indeks berkerumun di
AgreementStatus (AgreementId, EffectiveDate)
- sangat sedikit I / O mencari terjadi di sana. Tetapi jika itu pernah menjadi masalah, ada cara untuk menyelesaikannya, menggunakan pemicu, indeks / tampilan terwujud, peristiwa tingkat aplikasi, dll.Jangan khawatir tentang kinerja terlalu dini - itu lebih penting untuk mendapatkan desain yang benar, dan "benar" dalam hal ini berarti menggunakan database cara database dimaksudkan untuk digunakan, sebagai sistem transaksional .
sumber
Saat ini saya sedang bekerja dengan sistem saat ini di mana setiap tabel memiliki bendera Dihapus untuk penghapusan-lunak. Ini adalah kutukan dari semua keberadaan. Ini benar-benar merusak integritas relasional ketika pengguna dapat "menghapus" catatan dari satu tabel, namun anak-anak mencatat FK yang kembali ke tabel itu tidak kaskade yang dihapus dengan lembut. Benar-benar membuat data sampah setelah waktu berlalu.
Jadi, saya sarankan tabel sejarah terpisah.
sumber
Memecah meja menjadi dua adalah hal paling baik yang bisa dibayangkan.
Berikut adalah dua langkah sederhana yang akan saya rekomendasikan:
PS Maaf atas keterlambatan beberapa bulan dalam menjawab!
sumber
Jika Anda telah memulihkan akun yang dihapus ketika seseorang kembali dengan alamat email yang sama maka saya akan pergi dengan menjaga semua pengguna di tabel yang sama. Ini akan membuat proses pemulihan akun menjadi sepele.
Namun, saat Anda membuat akun baru, mungkin akan lebih mudah untuk memindahkan akun yang dihapus ke tabel terpisah. Sistem live tidak memerlukan informasi ini jadi jangan memaparkannya. Seperti yang Anda katakan itu membuat kueri lebih sederhana dan sangat mungkin lebih cepat pada kumpulan data yang lebih besar. Kode yang lebih sederhana juga lebih mudah dipelihara.
sumber
Anda tidak menyebutkan DBMS sedang digunakan. Jika Anda memiliki Oracle dengan lisensi yang tepat, Anda dapat mempertimbangkan mempartisi tabel pengguna menjadi dua partisi: pengguna aktif dan yang dihapus.
sumber