Bagaimana Anda merancang basis data untuk mendukung fitur penandaan berikut:
- item dapat memiliki sejumlah besar tag
- mencari semua item yang ditandai dengan serangkaian tag yang diberikan harus cepat (item harus memiliki SEMUA tag, jadi ini adalah pencarian-AND, bukan pencarian-OR)
- membuat / menulis item mungkin lebih lambat untuk mengaktifkan pencarian cepat / membaca
Idealnya, pencarian semua item yang ditandai dengan (setidaknya) satu set tag yang diberikan harus dilakukan menggunakan pernyataan SQL tunggal. Karena jumlah tag yang dicari serta jumlah tag pada item apa pun tidak diketahui dan mungkin tinggi, menggunakan GABUNGAN tidak praktis.
Ada ide?
Terima kasih atas semua jawaban sejauh ini.
Namun, jika saya tidak salah, jawaban yang diberikan menunjukkan bagaimana melakukan pencarian ATAU pada tag. (Pilih semua item yang memiliki satu atau lebih dari n tag). Saya mencari AND-search yang efisien. (Pilih semua item yang memiliki SEMUA n tag - dan mungkin lebih.)
sumber
select * from question q inner join question_has_tag qt where tag_id in (select tag_id from tags where (what we want) minus select tag_id from tags where (what we don't)
harus baik-baik saja dan diskalakan dengan asumsi indeks b-tree yang tepat ada di tabel tengahInilah artikel yang bagus tentang pemberian tag pada skema Database:
http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/
bersama dengan tes kinerja:
http://howto.philippkeller.com/2005/06/19/Tagsystems-performance-tests/
Perhatikan bahwa kesimpulan di sana sangat spesifik untuk MySQL, yang (setidaknya pada 2005 saat ditulis) memiliki karakteristik pengindeksan teks lengkap yang sangat buruk.
sumber
Saya tidak melihat masalah dengan solusi langsung: Tabel untuk item, tabel untuk tag, tabel silang untuk "pemberian tag"
Indeks pada tabel silang harus cukup optimal. Memilih item yang sesuai adalah
DAN penandaan akan menjadi
yang memang diakui, tidak begitu efisien untuk sejumlah besar tag pembanding. Jika Anda ingin mempertahankan jumlah tag dalam memori, Anda dapat membuat kueri untuk memulai dengan tag yang tidak sering, jadi DAN urutan akan dievaluasi lebih cepat. Bergantung pada jumlah tag yang diharapkan untuk dicocokkan dan harapan untuk mencocokkan satu pun dari mereka, ini bisa menjadi solusi yang baik, jika Anda mencocokkan 20 tag, dan berharap bahwa beberapa item acak akan cocok dengan 15 dari mereka, maka ini akan tetap berat pada database.
sumber
Saya hanya ingin menggarisbawahi bahwa artikel yang @Jeff Atwood ditautkan ( http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/ ) sangat teliti (Membahas manfaat dari 3 skema berbeda pendekatan) dan memiliki solusi yang baik untuk pertanyaan AND yang biasanya akan berkinerja lebih baik daripada apa yang telah disebutkan di sini sejauh ini (yaitu tidak menggunakan subquery yang berkorelasi untuk setiap istilah). Juga banyak hal bagus di komentar.
ps - Pendekatan yang dibicarakan semua orang di sini disebut sebagai solusi "Toxi" dalam artikel.
sumber
Anda mungkin ingin bereksperimen dengan solusi tidak-benar-database seperti implementasi Java Content Repository (misalnya Apache Jackrabbit ) dan menggunakan mesin pencari yang dibangun di atasnya seperti Apache Lucene .
Solusi ini dengan mekanisme caching yang tepat mungkin akan menghasilkan kinerja yang lebih baik daripada solusi buatan sendiri.
Namun, saya tidak benar-benar berpikir bahwa dalam aplikasi kecil atau menengah Anda akan memerlukan implementasi yang lebih canggih daripada database normal yang disebutkan dalam posting sebelumnya.
EDIT: dengan klarifikasi Anda, tampaknya lebih menarik untuk menggunakan solusi seperti JCR dengan mesin pencari. Itu akan sangat menyederhanakan program Anda dalam jangka panjang.
sumber
Metode termudah adalah membuat tabel tag .
Target_Type
- seandainya Anda menandai beberapa tabelTarget
- Kunci catatan ditandaiTag
- Teks dari sebuah tagMeminta data akan seperti:
PEMBARUAN
Berdasarkan kebutuhan Anda DAN kondisi, kueri di atas akan berubah menjadi sesuatu seperti ini
sumber
Saya akan menyarankan @Zizzencs kedua bahwa Anda mungkin menginginkan sesuatu yang tidak sepenuhnya (R) DB-centric
Entah bagaimana, saya percaya bahwa menggunakan bidang nvarchar biasa untuk menyimpan tag dengan beberapa caching / pengindeksan yang tepat dapat menghasilkan hasil yang lebih cepat. Tapi itu hanya aku.
Saya telah menerapkan sistem penandaan menggunakan 3 tabel untuk mewakili hubungan Banyak-ke-Banyak sebelumnya (Item Tag ItemTags), tapi saya kira Anda akan berurusan dengan tag di banyak tempat, saya dapat memberitahu Anda bahwa dengan 3 tabel harus dimanipulasi / ditanya secara bersamaan setiap saat pasti akan membuat kode Anda lebih kompleks.
Anda mungkin ingin mempertimbangkan apakah kompleksitas tambahannya sepadan.
sumber
Anda tidak akan dapat menghindari bergabung dan masih agak dinormalisasi.
Pendekatan saya adalah memiliki Tag Table.
Lalu, Anda memiliki kolom TagXREFID di tabel item Anda.
Kolom TagXREFID ini adalah FK ke tabel ke-3, saya akan menyebutnya TagXREF:
Jadi, untuk mendapatkan semua tag untuk item akan menjadi sesuatu seperti:
Dan untuk mendapatkan semua item untuk tag, saya akan menggunakan sesuatu seperti ini:
Untuk DAN sekelompok tag bersama-sama, Anda akan sedikit mengubah pernyataan di atas untuk menambahkan AND Tags.TagName = @ TagName1 AND Tags.TagName = @ TagName2 dll ... dan secara dinamis membuat kueri.
sumber
Yang ingin saya lakukan adalah memiliki sejumlah tabel yang mewakili data mentah, jadi dalam hal ini Anda akan melakukannya
Ini berfungsi cepat untuk waktu penulisan, dan menjaga semuanya tetap normal, tetapi Anda juga dapat mencatat bahwa untuk setiap tag, Anda harus bergabung dengan tabel dua kali untuk setiap tag lebih lanjut yang ingin Anda AND, jadi itu lambat dibaca.
Solusi untuk meningkatkan membaca adalah dengan membuat tabel caching pada perintah dengan mengatur prosedur tersimpan yang pada dasarnya membuat tabel baru yang mewakili data dalam format yang diratakan ...
Kemudian Anda dapat mempertimbangkan seberapa sering tabel Item Tagged harus tetap up to date, jika ada di setiap sisipan, lalu panggil prosedur tersimpan dalam peristiwa penyisipan kursor. Jika ini adalah tugas per jam, maka siapkan pekerjaan per jam untuk menjalankannya.
Sekarang untuk benar-benar pintar dalam pengambilan data, Anda harus membuat prosedur tersimpan untuk mendapatkan data dari tag. Daripada menggunakan kueri bersarang dalam pernyataan kasus besar-besaran, Anda ingin meneruskan satu parameter tunggal yang berisi daftar tag yang ingin Anda pilih dari database, dan mengembalikan kumpulan catatan Item. Ini akan menjadi yang terbaik dalam format biner, menggunakan operator bitwise.
Dalam format biner, mudah dijelaskan. Katakanlah ada empat tag untuk ditugaskan ke suatu item, dalam biner kita bisa menyatakan itu
Jika keempat tag ditugaskan ke objek, objek akan terlihat seperti ini ...
Jika hanya dua yang pertama ...
Maka itu hanya kasus menemukan nilai-nilai biner dengan 1s dan nol di kolom yang Anda inginkan. Menggunakan operator Bitwise SQL Server, Anda dapat memeriksa bahwa ada 1 di kolom pertama menggunakan kueri yang sangat sederhana.
Periksa tautan ini untuk mencari tahu lebih lanjut .
sumber
Mengutip apa yang dikatakan orang lain: triknya tidak ada dalam skema , itu ada dalam kueri .
Skema naif Entitas / Label / Tag adalah cara yang tepat untuk pergi. Namun seperti yang Anda lihat, tidak segera jelas cara melakukan kueri DAN dengan banyak tag.
Cara terbaik untuk mengoptimalkan kueri itu akan tergantung pada platform, jadi saya akan merekomendasikan untuk menandai ulang pertanyaan Anda dengan RDBS Anda dan mengubah judul menjadi sesuatu seperti "Cara optimal untuk melakukan DAN permintaan pada basis data penandaan".
Saya punya beberapa saran untuk MS SQL, tetapi akan menahan diri jika itu bukan platform yang Anda gunakan.
sumber
Variasi untuk jawaban di atas adalah mengambil id tag, mengurutkannya, menggabungkan sebagai ^ string yang dipisahkan dan hash mereka. Maka cukup kaitkan hash ke item. Setiap kombinasi tag menghasilkan kunci baru. Untuk melakukan pencarian DAN, cukup buat kembali hash dengan id tag yang diberikan dan cari. Mengubah tag pada suatu item akan menyebabkan hash dibuat ulang. Item dengan set tag yang sama berbagi kunci hash yang sama.
sumber
Jika Anda memiliki tipe array, Anda dapat melakukan agregat data yang diperlukan. Lihat jawaban ini di utas terpisah:
apa kegunaan dari tipe array?
sumber