Saya sengaja meninggalkan ini cukup jelas pada awalnya. I'm mencari dan pembahasan isu-isu penting lebih dari saya'm keras mencari jawaban.
I'm di tengah-tengah merancang sebuah aplikasi yang melakukan sesuatu seperti manajemen portofolio. Desain yang saya miliki sejauh ini adalah
Pertanyaan saya adalah tentang sifat temporal dari hal-hal ini. Masalah muncul, kemudian memudar. Solusi memiliki resolusi yang diharapkan saat ini, tapi itu mungkin dimodifikasi seperti yang dikembangkan. Tingkat hubungan yang mungkin berubah dari waktu ke waktu sebagai masalah dan solusi berkembang.
Jadi, pertanyaannya: apa desain yang terbaik untuk versi dari hal-hal ini sehingga saya bisa mendapatkan kedua saat ini dan perspektif sejarah dari portofolio saya?
Kemudian: mungkin aku harus membuat pertanyaan yang lebih spesifik, meskipun @Eric Jenggot's jawaban bernilai up.
I've dianggap tiga desain database. I'll cukup dari masing-masing untuk menunjukkan kelemahan mereka. Pertanyaan saya adalah: yang sempurna, atau anda dapat memikirkan sesuatu yang lebih baik?
table problems
int id | string name | text description | datetime created_at | int previous_version_id
foreign key previous_version_id -> problems.id
Ini bermasalah karena setiap kali aku mau versi baru, saya harus menduplikasi seluruh baris, termasuk yang lama description
kolom.
table problems
int id | string name | text description | datetime created_at
Ini hanya bergerak hubungan dari Masalah dan Solusi tabel ke dalam Hubungan tabel. Sama duplikasi masalah, tapi mungkin sedikit "cleaner" karena saya sudah punya abstrak Hubungan konsep.
table problems
int id
table attributes
int id | int thing_id | string thing_type | string name | string value | datetime created_at | int previous_version_id
foreign key (thing_id, thing_type) -> problems.id or solutions.id
foreign key previous_version_id -> attributes.id
Ini berarti bahwa untuk memuat versi saat ini dari Masalah atau Solusi yang harus saya ambil semua versi dari atribut, mengurutkan mereka berdasarkan tanggal dan kemudian gunakan saat ini. Yang mungkin tidak akan mengerikan. Apa yang tampaknya benar-benar buruk bagi saya adalah bahwa saya dapat't jenis-cek sifat-sifat ini dalam database. Bahwa nilai
kolom untuk teks. Saya dapat membuat kolom nama
referensi menjadi terpisah attribute_names
tabel yang memiliki jenis
kolom, tapi itu doesn't memaksa jenis yang tepat di atribut
tabel.
kemudian masih: respon ke @Eric Jenggot's komentar tentang multi-tabel foreign key:
Sayangnya, apa yang saya've dijelaskan adalah sederhana: hanya ada dua jenis hal-Hal (Masalah dan Solusi). Aku benar-benar memiliki sekitar 9 atau 10 jenis yang berbeda dari hal-Hal, jadi saya'd memiliki 9 atau 10 kolom foreign key di bawah strategi anda. Saya ingin menggunakan single-meja warisan, tetapi hal-Hal yang memiliki begitu banyak kesamaan yang akan sangat boros untuk menggabungkan mereka ke dalam satu tabel.
Hmm, kedengarannya seperti situs ini...
Sejauh desain database akan pergi, sebuah versi sistem seperti SVN, di mana anda tidak pernah benar-benar melakukan update, hanya sisipan (dengan nomor versi) ketika hal-hal berubah, mungkin apa yang anda butuhkan. Ini disebut MVCC, Multi-Nilai Concurrency Control. Wiki adalah salah satu contoh yang baik dari ini.
@Gayus
foreign key (thing_id, thing_type) -> problems.id or solutions.id
Berhati-hati dengan jenis-jenis "multiarah" kunci asing. Pengalaman saya menunjukkan bahwa performa query yang menderita secara dramatis ketika anda bergabung kondisi untuk memeriksa jenis sebelum mencari tahu mana meja untuk bergabung di. Itu doesn't tampak elegan tapi nullable
problem_id and solution_id
akan bekerja jauh lebih baik.
Tentu saja, performa query juga akan menderita dengan MVCC desain ketika anda harus menambahkan check untuk mendapatkan versi terbaru dari rekor. Tradeoff adalah bahwa anda tidak perlu khawatir tentang pertentangan dengan update.
Bagaimana anda berpikir tentang hal ini:
meja masalah int id | string nama | deskripsi teks | datetime created_at
tabel problems_revisions int revisi | int id | string nama | deskripsi teks | datetime created_at foreign key id -> masalah.id
Sebelum update, anda harus melakukan insert tambahan dalam revisi meja. Ini tambahan menyisipkan cepat, namun, ini adalah apa yang anda harus membayar untuk
Saya kira ada's
Memindahkan Hal yang umum atribut menjadi satu-warisan meja, kemudian tambahkan sebuah custom_attributes
tabel. Hal ini membuat asing-tombol yang lebih sederhana, mengurangi duplikasi, dan memungkinkan fleksibilitas. Itu doesn't memecahkan masalah jenis-keselamatan untuk atribut tambahan. Ia juga menambahkan sedikit kompleksitas sejak ada dua cara untuk suatu Hal untuk memiliki atribut sekarang.
Jika description
dan lain bidang besar tetap dalam hal-Hal tabel, meskipun, itu juga doesn't memecahkan duplikasi-masalah ruang.
table things
int id | int type | string name | text description | datetime created_at | other common fields...
foreign key type -> thing_types.id
table custom_attributes
int id | int thing_id | string name | string value
foreign key thing_id -> things.id
It's merupakan ide yang baik untuk memilih sebuah struktur data yang membuat pertanyaan umum yang anda minta dari model yang mudah untuk menjawab. It's kemungkinan besar bahwa anda're tertarik pada posisi saat ini sebagian besar waktu. Pada kesempatan tersebut, anda akan ingin untuk mengebor ke dalam sejarah untuk masalah tertentu dan solusi.
Aku akan memiliki tabel untuk masalah, solusi, dan hubungan yang mewakili posisi saat ini. Ada juga akan menjadi problem_history
, solution_history
, dll meja. Ini akan menjadi anak tabel dari masalah, tetapi juga berisi kolom tambahan untuk VersionNumber
dan EffectiveDate
. Kunci akan menjadi (ProblemId
, VersionNumber
).
Ketika anda memperbarui masalah, anda akan menulis nilai-nilai lama ke problem_history
tabel. Titik waktu kueri oleh karena itu mungkin anda bisa memilih problem_history
rekor yang berlaku-pada tanggal tertentu.
Di mana saya've melakukan ini sebelumnya, saya juga telah membuat sebuah view untuk UNI masalah
dan problem_history
seperti ini kadang-kadang berguna dalam berbagai pertanyaan.
Opsi 1 membuat sulit untuk query situasi saat ini, karena semua data historis dicampur dengan data anda saat ini.
Pilihan 3 ini akan menjadi buruk bagi kinerja permintaan dan jahat untuk kode terhadap anda'll dapat mengakses banyak baris untuk apa yang harus menjadi query sederhana.