Latar belakang saya lebih pada pemrograman web daripada administrasi basis data, jadi tolong perbaiki saya jika saya menggunakan terminologi yang salah di sini. Saya mencoba mencari cara terbaik untuk mendesain database untuk aplikasi yang akan saya koding.
Situasi: Saya punya Laporan di satu meja dan Rekomendasi di meja lain. Setiap Laporan dapat memiliki banyak Rekomendasi. Saya juga memiliki tabel terpisah untuk Kata Kunci (untuk menerapkan penandaan). Namun, saya ingin memiliki hanya satu set kata kunci yang diterapkan pada Laporan dan Rekomendasi sehingga pencarian pada kata kunci memberi Anda Laporan dan Rekomendasi sebagai hasil.
Inilah struktur yang saya mulai dengan:
Reports
----------
ReportID
ReportName
Recommendations
----------
RecommendationID
RecommendationName
ReportID (foreign key)
Keywords
----------
KeywordID
KeywordName
ObjectKeywords
----------
KeywordID (foreign key)
ReportID (foreign key)
RecommendationID (foreign key)
Secara naluriah, saya merasa seperti ini tidak optimal dan saya harus memiliki objek taggable saya mewarisi dari orang tua yang sama, dan meminta orang tua komentar itu ditandai, yang akan memberikan struktur berikut:
BaseObjects
----------
ObjectID (primary key)
ObjectType
Reports
----------
ObjectID_Report (foreign key)
ReportName
Recommendations
----------
ObjectID_Recommendation (foreign key)
RecommendationName
ObjectID_Report (foreign key)
Keywords
----------
KeywordID (primary key)
KeywordName
ObjectKeywords
----------
ObjectID (foreign key)
KeywordID (foreign key)
Haruskah saya pergi dengan struktur kedua ini? Apakah saya melewatkan masalah penting di sini? Juga, jika saya menggunakan yang kedua, apa yang harus saya gunakan sebagai nama non-generik untuk menggantikan "Objek"?
Memperbarui:
Saya menggunakan SQL Server untuk proyek ini. Ini adalah aplikasi internal dengan sejumlah kecil pengguna non-konkuren, jadi saya tidak mengantisipasi beban tinggi. Dalam hal penggunaan, kata kunci kemungkinan akan digunakan hemat. Cukup banyak hanya untuk keperluan pelaporan statistik. Dalam hal itu, solusi apa pun yang saya gunakan mungkin hanya akan memengaruhi pengembang mana pun yang perlu mempertahankan sistem ini di masa depan ... tapi saya pikir sebaiknya menerapkan praktik yang baik kapan pun saya bisa. Terima kasih atas semua wawasannya!
sumber
Jawaban:
Masalah dengan contoh pertama Anda adalah tabel tri-link. Apakah itu akan memerlukan salah satu kunci asing pada laporan atau rekomendasi untuk selalu NULL sehingga kata kunci hanya menghubungkan satu cara atau yang lain?
Dalam kasus contoh kedua Anda, bergabung dari basis ke tabel turunan sekarang mungkin memerlukan penggunaan pemilih jenis atau GABUNGAN KIRI tergantung pada bagaimana Anda melakukannya.
Mengingat itu, mengapa tidak membuatnya eksplisit dan menghilangkan semua NULL dan KIRI GABUNG?
Dalam skenario ini saat Anda menambahkan sesuatu yang perlu ditandai, Anda cukup menambahkan tabel entitas dan tabel tautan.
Kemudian hasil pencarian Anda terlihat seperti ini (lihat masih ada pemilihan jenis yang terjadi dan mengubahnya menjadi generik pada tingkat hasil objek jika Anda menginginkan daftar hasil tunggal):
Tidak peduli apa, di suatu tempat akan ada pemilihan jenis dan semacam percabangan terjadi.
Jika Anda melihat bagaimana Anda akan melakukan ini dalam opsi 1 Anda, itu serupa tetapi dengan pernyataan KASUS atau GABUNG KIRI dan COALESCE. Saat Anda memperluas opsi 2 dengan lebih banyak hal yang ditautkan, Anda harus terus menambahkan lebih banyak GABUNG KIRI di mana hal-hal yang biasanya TIDAK ditemukan (objek yang ditautkan hanya dapat memiliki satu tabel turunan yang valid).
Saya tidak berpikir ada sesuatu yang secara fundamental salah dengan pilihan Anda 2, dan Anda benar-benar bisa membuatnya terlihat seperti proposal ini dengan menggunakan pandangan.
Dalam opsi Anda 1, saya mengalami kesulitan melihat mengapa Anda memilih tabel tri-link.
sumber
Pertama, perhatikan bahwa solusi ideal tergantung sampai batas tertentu pada RDBMS yang Anda gunakan. Saya akan memberikan jawaban standar dan spesifik PostgreSQL.
Normalisasi, Jawaban Standar
Jawaban standar adalah memiliki dua tabel bergabung.
Misalkan kita memiliki tabel kita:
Pendekatan ini mengikuti semua aturan normalisasi standar, dan tidak melanggar prinsip normalisasi database tradisional. Ini harus bekerja pada RDBMS apa pun.
Jawaban spesifik PostgreSQL, desain N1NF
Pertama, kata mengapa PostgreSQL berbeda. PostgreSQL mendukung sejumlah cara yang sangat berguna untuk menggunakan indeks di atas array, terutama menggunakan apa yang dikenal sebagai indeks GIN. Ini dapat menguntungkan kinerja sedikit jika digunakan dengan benar di sini. Karena PostgreSQL dapat "menjangkau" tipe data dengan cara ini, asumsi dasar atomisitas dan normalisasi agak bermasalah untuk diterapkan secara kaku di sini. Jadi untuk alasan ini, rekomendasi saya adalah untuk melanggar aturan atomisitas bentuk normal pertama dan mengandalkan indeks GIN untuk kinerja yang lebih baik.
Catatan kedua di sini adalah bahwa sementara ini memberikan kinerja yang lebih baik, ini menambah beberapa sakit kepala karena Anda akan memiliki beberapa pekerjaan manual yang harus dilakukan untuk mendapatkan integritas referensial untuk bekerja dengan benar. Jadi tradeoff di sini adalah kinerja untuk pekerjaan manual.
Sekarang kita harus menambahkan pemicu untuk memastikan bahwa kata kunci dikelola dengan benar.
Kedua, kita harus memutuskan apa yang harus dilakukan ketika kata kunci dihapus. Seperti yang ada sekarang, kata kunci yang dihapus dari tabel kata kunci tidak akan mengalir ke bidang kata kunci. Mungkin ini diinginkan dan mungkin juga tidak. Hal paling sederhana yang harus dilakukan adalah batasi saja penghapusan selalu dan berharap Anda akan menangani kasus ini secara manual jika muncul (gunakan pemicu untuk keamanan di sini). Opsi lain mungkin menulis ulang setiap nilai kata kunci di mana kata kunci itu ada untuk menghapusnya. Sekali lagi pemicu akan menjadi cara untuk melakukan itu juga.
Keuntungan besar dari solusi ini adalah Anda dapat mengindeks untuk pencarian sangat cepat berdasarkan kata kunci, dan Anda dapat menarik semua tag tanpa bergabung. Kerugiannya adalah bahwa menghapus kata kunci itu menyakitkan, dan tidak akan berkinerja baik bahkan pada hari yang baik. Ini mungkin dapat diterima karena ini adalah peristiwa langka dan dapat dikirim ke proses latar belakang tetapi merupakan tradeoff yang layak dipahami.
Mengkritik Solusi Pertama Anda
Masalah sebenarnya dengan solusi pertama Anda adalah bahwa Anda tidak memiliki kunci yang mungkin pada ObjectKeywords. Akibatnya Anda memiliki masalah di mana Anda tidak dapat menjamin bahwa setiap kata kunci diterapkan untuk setiap objek hanya sekali.
Solusi kedua Anda sedikit lebih baik. Jika Anda tidak menyukai solusi lain yang ditawarkan, saya sarankan menggunakannya. Namun saya menyarankan untuk menyingkirkan keyword_id dan hanya bergabung pada teks kata kunci. Itu menghilangkan bergabung tanpa denormalisasi.
sumber
Saya akan menyarankan dua struktur terpisah:
Dengan cara ini Anda tidak memiliki semua id entitas yang mungkin dalam tabel yang sama (yang tidak terlalu skalabel, dan bisa membingungkan), dan Anda tidak memiliki tabel dengan "id objek" generik yang harus disambiguasi di tempat lain menggunakan
base_object
tabel, yang akan bekerja, tapi saya pikir desainnya terlalu rumit.sumber
BaseObjects
tabel pada read-through pertama saya, dan saya pikir saya melihat deskripsi untuk tabel di manaobject_id
dapat menunjuk ke ID di tabel mana pun .Dalam pengalaman saya, inilah yang dapat Anda lakukan.
Dan untuk hubungan antara kata kunci, laporan, dan rekomendasi, Anda dapat melakukan salah satu dari dua opsi: Opsi A:
Ini memungkinkan hubungan langsung dari Laporan ke Rekomendasi, ke Kata Kunci dan akhirnya ke Kata Kunci. Opsi B:
Opsi A adalah yang lebih mudah untuk diterapkan dan dikelola karena akan memiliki constratints dari database untuk menangani integritas data dan tidak akan membiarkan penyisipan data yang tidak valid.
Opsi B meskipun memerlukan sedikit lebih banyak pekerjaan karena Anda perlu kode identifikasi hubungan. Lebih fleksibel dalam jangka panjang, jika kebetulan di beberapa titik di masa depan Anda perlu menambahkan kata kunci ke item lain selain laporan atau rekomendasi Anda hanya perlu menambahkan identifikasi dan menggunakan langsung tabel.
sumber