Desain basis data - Menyimpan status atau menghitung kondisi setiap saat?

17

Katakanlah saya memiliki aplikasi basis data relasional dan objek "pengguna" dan objek "pesan". Sekarang saya ingin menunjukkan jumlah pesan yang belum dibaca kepada pengguna ini.

Apa cara terbaik untuk mengarsipkan ini? Apakah saya memperkenalkan bidang dalam pengguna dan menghitungnya jika pengguna menerima pesan dan mengurangi jumlah jika ia membacanya? Atau apakah saya menjalankan kueri setiap kali untuk menghitung jumlah pesan untuk pengguna yang ditandai sebagai belum dibaca?

Saya pikir pendekatan pertama lebih rumit dan rawan kesalahan, tetapi akan melakukan lebih baik daripada pendekatan kedua.

Bagaimana ini biasanya dilakukan atau apa pendekatan yang lebih baik?

jan
sumber
1
Tergantung pada sejumlah faktor: apakah DB Anda dipartisi? Berapa banyak baris / pengguna yang Anda harapkan? Berapa ukuran total DB yang Anda harapkan (atau berapa total pengguna)? Berapa banyak permintaan per detik yang Anda harapkan? Semua ini tidak harus akurat, tetapi beberapa ide kasar ...
Omer Iqbal
10
+1 Ini adalah pertanyaan basis data relasional klasik. Menormalkan, atau tidak menormalkan? Itu pertanyaannya. Apakah lebih mulia dalam skema menderita sling dan panah duplikasi keterlaluan, atau mengambil pemicu, dan dengan menggunakan, akhiri?
Ross Patterson
Saya berpendapat jika ini bukan Rel klasik. db. pertanyaan, seharusnya sudah ada jawaban di situs, ini harus ditutup sebagai DUP, atau kami tidak punya jawaban dan ini harus dibiarkan terbuka.
mattnz

Jawaban:

14

Bagaimana ini biasanya dilakukan atau apa pendekatan yang lebih baik?

Pendekatan terbaik adalah mencobanya terlebih dahulu tanpa bidang tambahan, mengukur kinerja, dan jika ternyata terlalu lambat, Anda mencoba untuk mengoptimalkan. Ini bisa berarti untuk beralih ke pendekatan pertama Anda menggunakan bidang tambahan, tetapi Anda harus mempertimbangkan untuk menguji opsi lain juga, misalnya, menempatkan indeks tambahan pada bidang gabungan ("belum dibaca", "userID") pada pesan Anda.

Doc Brown
sumber
2
Pendekatan terbaik adalah (ikuti metode yang lebih sederhana terlebih dahulu). Aturan umum lebih baik daripada spesifik, fwiw. (+1 untuk "tes!".)
DougM
9

Solusi buku teks sesuai dengan teori basis data adalah tidak memiliki nilai dalam database Anda yang bergantung pada nilai-nilai data lain, karena ini adalah dependensi transitif . Memiliki bidang yang merupakan nilai yang dihitung berdasarkan bidang lain merupakan pelanggaran normalisasi, karena itu mengarah pada informasi yang berlebihan.

Namun, terkadang apa yang dikatakan buku teks dan apa metode yang paling praktis dalam praktik berbeda. Menghitung jumlah pesan yang belum dibaca setiap tampilan halaman bisa menjadi operasi yang cukup mahal. Caching angka di user-tabel akan jauh lebih baik untuk kinerja. Biayanya adalah bahwa inkonsistensi mungkin ada dalam database: Mungkin ada kemungkinan pesan dihapus, ditambahkan atau dibaca tanpa mengingat untuk juga memperbarui konter yang belum dibaca.

Philipp
sumber
4
Masalah konsistensi mudah dijilat dengan pemicu yang menyesuaikan penghitung pada INSERTatau DELETE. (Atau UPDATE, untuk menjelaskan perubahan pemilik pesan.). DBMS yang baik akan melakukan operasi dan menjalankan pemicu dalam transaksi yang sama, sehingga semua atau tidak sama sekali akan terjadi.
Blrfl
4

Masalah potensial adalah kinerja dan Anda belum memiliki masalah kinerja. Ada banyak hal yang dapat Anda lakukan tergantung pada database pilihan untuk menangani ini dalam solusi # 1: pengindeksan, perangkat keras, caching, dll. Ini semua tergantung pada seberapa sering pengguna perlu mendapatkan jumlah pesan yang belum dibaca saat ini. Banyak dari pilihan ini tidak memerlukan pengkodean khusus di sisi aplikasi, sehingga Anda dapat menerapkannya dengan perubahan kode atau sangat sedikit. Membuatnya lebih mudah untuk tumbuh dengan aplikasi.

Setelah pengguna menghubungkan / masuk, mendapatkan hitungan dari basis data tidak terlalu buruk. Apakah aplikasi Anda akan terus memperbarui daftar pesan seperti email? Mendapatkan hitungan yang belum dibaca dari sini tidak memerlukan perjalanan lain ke database dan untuk mendapatkan pesan baru akan tetap melakukan perjalanan db.

Melakukan perjalanan ke db setiap kali pesan dibaca untuk menandai IsRead? bidang sudah cukup tanpa perhitungan ulang bidang lain.

Dengan solusi # 2 (menyimpan hitungan dalam bidang / pada disk), akankah Anda memerlukan rutin untuk membangun kembali secara berkala / menghitung ulang bidang ini saat ada masalah? Dan selalu ada masalah. Apakah Anda akan membungkus semua ini dalam suatu transaksi? Setiap kali seseorang mengirim pesan kepada orang lain, pesan itu bisa gagal karena tidak dapat memperbarui UnreadCount pengguna penerima karena kunci tabel Pengguna? Atau Anda akan membuat tabel terpisah untuk bidang ini?

JeffO
sumber
+1 untuk menyebutkan masalah kinerja dengan menjaga agar bidang hitungan selalu terbarui
winkbrace
0

Cara saya akan melakukannya adalah dengan mengeksekusi query setiap waktu, yaitu pendekatan kedua Anda. Pastikan Anda menambahkan indeks di tabel pesan di kolom yang berfungsi sebagai kunci asing ke tabel pengguna untuk meningkatkan kinerja kueri Anda.

Kemudian seperti yang dikatakan Doc, ukur kinerja pendekatan ini dan kemudian Anda akan dapat mengetahui apakah Anda perlu mengambil jalur yang berbeda.

Jose B
sumber