Menyimpan JSON dalam database vs. memiliki kolom baru untuk setiap kunci

214

Saya menerapkan model berikut untuk menyimpan data terkait pengguna di tabel saya - Saya punya 2 kolom - uid(kunci utama) dan metakolom yang menyimpan data lain tentang pengguna dalam format JSON.

 uid   | meta
--------------------------------------------------
 1     | {name:['foo'], 
       |  emailid:['[email protected]','[email protected]']}
--------------------------------------------------
 2     | {name:['sann'], 
       |  emailid:['[email protected]','[email protected]']}
--------------------------------------------------

Apakah ini cara yang lebih baik (kinerja-bijaksana, desain-bijaksana) dari model satu-kolom-per-properti, di mana meja akan memiliki banyak kolom seperti uid, name, emailid.

Yang saya suka tentang model pertama adalah, Anda dapat menambahkan sebanyak mungkin bidang tidak ada batasan.

Juga, saya bertanya-tanya, sekarang saya telah menerapkan model pertama. Bagaimana cara saya melakukan kueri, seperti, saya ingin mengambil semua pengguna yang memiliki nama seperti 'foo'?

Pertanyaan - Manakah cara terbaik untuk menyimpan data terkait pengguna (dengan mengingat bahwa jumlah bidang tidak diperbaiki) dalam basis data menggunakan - JSON atau kolom per bidang? Juga, jika model pertama diterapkan, bagaimana cara query database seperti dijelaskan di atas? Haruskah saya menggunakan kedua model, dengan menyimpan semua data yang dapat dicari oleh kueri di baris terpisah dan data lainnya di JSON (apakah baris berbeda)?


Memperbarui

Karena tidak akan ada terlalu banyak kolom di mana saya perlu melakukan pencarian, apakah sebaiknya menggunakan kedua model? Kunci-per-kolom untuk data yang saya butuhkan untuk mencari dan JSON untuk orang lain (dalam database MySQL yang sama)?

ShuklaSannidhya
sumber
40
pertanyaan bagus! tetapi mengapa Anda tidak menerima jawaban? yang akan membantu pengguna lain (seperti saya)
Sahar Ch.

Jawaban:

198

Diperbarui 4 Juni 2017

Mengingat bahwa pertanyaan / jawaban ini telah mendapatkan popularitas, saya pikir itu layak diperbarui.

Ketika pertanyaan ini awalnya diposting, MySQL tidak memiliki dukungan untuk tipe data JSON dan dukungan di PostgreSQL masih dalam tahap awal. Sejak 5.7, MySQL sekarang mendukung tipe data JSON (dalam format penyimpanan biner), dan PostgreSQL JSONB telah matang secara signifikan. Kedua produk menyediakan tipe JSON yang dapat menyimpan dokumen sewenang-wenang, termasuk dukungan untuk mengindeks kunci tertentu dari objek JSON.

Namun, saya masih mendukung pernyataan asli saya bahwa preferensi default Anda, ketika menggunakan database relasional, masih harus berupa kolom-per-nilai. Database relasional masih dibangun dengan asumsi bahwa data di dalamnya akan dinormalisasi dengan cukup baik. Perencana permintaan memiliki informasi pengoptimalan yang lebih baik ketika melihat kolom daripada ketika melihat kunci dalam dokumen JSON. Kunci asing dapat dibuat antar kolom (tetapi tidak antara kunci dalam dokumen JSON). Yang penting: jika sebagian besar skema Anda cukup volatile untuk membenarkan menggunakan JSON, Anda mungkin ingin setidaknya mempertimbangkan jika database relasional adalah pilihan yang tepat.

Yang mengatakan, beberapa aplikasi yang sempurna berhubungan atau berorientasi pada dokumen. Sebagian besar aplikasi memiliki campuran keduanya. Berikut adalah beberapa contoh di mana saya secara pribadi menemukan JSON berguna dalam database relasional:

  • Saat menyimpan alamat email dan nomor telepon untuk kontak, tempat menyimpannya sebagai nilai dalam array JSON jauh lebih mudah dikelola daripada beberapa tabel terpisah

  • Menyimpan preferensi pengguna kunci / nilai sewenang-wenang (di mana nilainya bisa boolean, tekstual, atau numerik, dan Anda tidak ingin memiliki kolom terpisah untuk tipe data yang berbeda)

  • Menyimpan data konfigurasi yang tidak memiliki skema yang ditentukan (jika Anda sedang membangun Zapier, atau IFTTT dan perlu menyimpan data konfigurasi untuk setiap integrasi)

Saya yakin ada yang lain juga, tetapi ini hanya beberapa contoh singkat.

Jawaban Asli

Jika Anda benar-benar ingin dapat menambahkan bidang sebanyak yang Anda inginkan tanpa batasan (selain batas ukuran dokumen sewenang-wenang), pertimbangkan solusi NoSQL seperti MongoDB.

Untuk database relasional: gunakan satu kolom per nilai. Menempatkan gumpalan JSON di kolom membuatnya hampir tidak mungkin untuk permintaan (dan sangat lambat ketika Anda benar-benar menemukan permintaan yang berfungsi).

Database relasional mengambil keuntungan dari tipe data saat pengindeksan, dan dimaksudkan untuk diimplementasikan dengan struktur yang dinormalisasi .

Sebagai catatan tambahan: ini bukan untuk mengatakan Anda tidak boleh menyimpan JSON dalam database relasional. Jika Anda menambahkan metadata sebenarnya, atau jika JSON Anda menggambarkan informasi yang tidak perlu ditanyakan dan hanya digunakan untuk tampilan, mungkin akan terlalu sulit untuk membuat kolom terpisah untuk semua titik data.

Colin M
sumber
1
Karena tidak akan ada terlalu banyak kolom di mana saya perlu melakukan pencarian, apakah sebaiknya menggunakan kedua model? Kunci-per-kolom untuk data yang saya butuhkan untuk mencari dan JSON untuk orang lain (dalam database MySQL yang sama)?
ShuklaSannidhya
3
@Sann Anda harus menggunakan kolom per nilai untuk data yang ingin Anda baca atau sering kueri. Memasukkan nama seseorang di JSON tidak masuk akal karena, meskipun Anda tidak cenderung untuk menanyakannya, Anda cenderung sangat membutuhkannya . Itu banyak decoding boros di sisi aplikasi Anda. Kecuali jika Anda benar - benar merasa bahwa data Anda lebih baik direpresentasikan sebagai JSON (dan percayalah, mungkin tidak), Anda tidak boleh menggunakan itu.
Colin M
5
" virtually impossible to query" - hari ini psql memungkinkan Anda untuk mencari dan mengindeks jsonb
ted
1
@ terbukti benar. Namun, pada saat penulisan jawaban ini tidak benar-benar tersedia. Juga, pertanyaan ini merujuk pada MySQL yang tidak memiliki kapabilitas.
Colin M
3
@ColinM, ya, saya sadar komentar saya 3 tahun lebih muda dari posting Anda. Alasan saya meninggalkannya adalah karena ini dapat membantu dan mengubah keputusan untuk orang lain. Adapun referensi ke MySQL: bisa benar, tetapi ada "For relational databases"dalam jawaban Anda = P
ted
69

Seperti kebanyakan hal "itu tergantung". Tidak benar atau salah / baik atau buruk dalam dirinya sendiri untuk menyimpan data dalam kolom atau JSON. Itu tergantung pada apa yang perlu Anda lakukan dengannya nanti. Bagaimana cara Anda memperkirakan mengakses data ini? Apakah Anda perlu referensi silang data lain?

Orang lain telah menjawab dengan cukup baik apa trade-off teknisnya.

Tidak banyak orang yang membahas bahwa aplikasi dan fitur Anda berkembang seiring waktu dan bagaimana keputusan penyimpanan data ini memengaruhi tim Anda.

Karena salah satu godaan menggunakan JSON adalah untuk menghindari migrasi skema dan jadi jika tim tidak disiplin, sangat mudah untuk memasukkan pasangan kunci / nilai lain ke dalam bidang JSON. Tidak ada migrasi untuk itu, tidak ada yang ingat untuk apa itu. Tidak ada validasi untuk itu.

Tim saya menggunakan JSON di sepanjang kolom sisi tradisional di postgres dan pada awalnya itu yang terbaik sejak memotong roti. JSON sangat menarik dan kuat, sampai suatu hari kami menyadari bahwa fleksibilitas datang pada biaya dan tiba-tiba merupakan titik yang sangat menyakitkan. Kadang-kadang titik itu merayap dengan sangat cepat dan kemudian menjadi sulit untuk berubah karena kami telah membangun banyak hal lain di atas keputusan desain ini.

Lembur, menambahkan fitur baru, memiliki data dalam JSON menyebabkan kueri tampak lebih rumit daripada apa yang mungkin ditambahkan jika kita terjebak pada kolom tradisional. Jadi kami mulai memancing nilai-nilai kunci tertentu kembali ke kolom sehingga kami bisa membuat gabungan dan membuat perbandingan antara nilai-nilai. Ide buruk. Sekarang kami memiliki duplikasi. Pengembang baru akan muncul dan menjadi bingung? Nilai apa yang harus saya simpan kembali? JSON satu atau kolom?

Bidang JSON menjadi laci sampah untuk potongan kecil ini dan itu. Tidak ada validasi data pada tingkat basis data, tidak ada konsistensi atau integritas antara dokumen. Itu mendorong semua tanggung jawab itu ke dalam aplikasi alih-alih mendapatkan tipe keras dan memeriksa kendala dari kolom tradisional.

Melihat ke belakang, JSON memungkinkan kami untuk beralih dengan sangat cepat dan mendapatkan sesuatu dari pintu. Itu bagus. Namun setelah kami mencapai ukuran tim tertentu, fleksibilitasnya juga memungkinkan kami untuk menggantung diri dengan tali panjang hutang teknis yang kemudian memperlambat kemajuan evolusi fitur selanjutnya. Gunakan dengan hati-hati.

Pikirkan panjang dan keras tentang apa sifat data Anda. Ini adalah dasar dari aplikasi Anda. Bagaimana data akan digunakan seiring waktu. Dan bagaimana mungkin MENGUBAH?

Homan
sumber
7
"Fleksibilitas itu juga memungkinkan kami untuk menggantung diri dengan seutas tali hutang teknis" metafora yang sangat bagus!
Antoine Gallix
Setelah bertahun-tahun berkembang dan bekerja dengan orang yang berbeda, jika saya harus menulis tentang hal ini saya akan menulis hal yang sama Ada begitu banyak pengembang sekarang, di mana banyak dari mereka bahkan dengan pengalaman bertahun-tahun mereka tidak benar-benar naik level. Kita harus menjaga semuanya tetap sederhana dan bagi saya 2 hal yang harus selalu kita pertimbangkan yang dapat "kerangka" keberhasilan adalah skalabilitas dan pemeliharaan kode.
JohnnyJaxs
27

Hanya melemparkannya ke luar sana, tetapi WordPress memiliki struktur untuk hal-hal semacam ini (setidaknya WordPress adalah tempat pertama yang saya amati, mungkin berasal dari tempat lain).

Ini memungkinkan kunci tanpa batas, dan lebih cepat untuk mencari daripada menggunakan gumpalan JSON, tetapi tidak secepat beberapa solusi NoSQL.

uid   |   meta_key    |   meta_val
----------------------------------
1         name            Frank
1         age             12
2         name            Jeremiah
3         fav_food        pizza
.................

EDIT

Untuk menyimpan histori / beberapa kunci

uid   | meta_id    |   meta_key    |   meta_val
----------------------------------------------------
1        1             name            Frank
1        2             name            John
1        3             age             12
2        4             name            Jeremiah
3        5             fav_food        pizza
.................

dan permintaan melalui sesuatu seperti ini:

select meta_val from `table` where meta_key = 'name' and uid = 1 order by meta_id desc
Adam
sumber
1
Saya ingin tahu apakah solusi NoSQL benar-benar berkinerja lebih baik daripada permintaan relasional pada kunci indeks yang benar. Saya menduga itu harus kurang lebih sama pada contoh 1 tingkat seperti ini.
Bruno
+1. Saya juga memperhatikannya! Tapi itu memberi Anda meja besar (dalam hal baris). Anda juga tidak dapat menyimpan banyak nilai, katakanlah, jika pengguna mengubah namanya, tetapi saya juga ingin mempertahankan nama lama, dalam hal ini saya akan memerlukan model data tipe JSON.
ShuklaSannidhya
@Sann, jika Anda ingin menyimpan nilai lama di JSON, Anda juga harus mengganti nama kunci: Anda dapat melakukannya dengan EAV (yang merupakan contoh ini) atau JSON. Tidak terlalu berbeda.
Bruno
Itu memberi Anda tabel besar, tetapi untuk nilai duplikat, Anda mengalami masalah yang sama dengan JSON - Anda tidak dapat memiliki kunci duplikat di tingkat yang sama (misalnya dua kunci "nama") dan mengharapkan perilaku yang dapat diprediksi.
Adam
Tentu Anda tidak dapat memiliki kunci duplikat, tetapi dapat memiliki array yang terkait dengan kunci itu. Lihat emailidkunci pada contoh yang saya berikan dalam pertanyaan saya.
ShuklaSannidhya
13

kelemahan dari pendekatan ini persis seperti yang Anda sebutkan:

itu membuatnya SANGAT lambat untuk menemukan sesuatu, karena setiap kali Anda perlu melakukan pencarian teks di atasnya.

nilai per kolom sebagai gantinya cocok dengan seluruh string.

Pendekatan Anda (data berbasis JSON) tidak masalah untuk data yang tidak perlu Anda cari, dan hanya perlu ditampilkan bersama dengan data normal Anda.

Sunting: Hanya untuk memperjelas, hal di atas berlaku untuk database relasional klasik. NoSQL menggunakan JSON secara internal, dan mungkin merupakan opsi yang lebih baik jika itu adalah perilaku yang diinginkan.

Nick Andriopoulos
sumber
1
Jadi maksud Anda, saya harus menggunakan keduanya. Kunci-per-kolom untuk data yang saya butuhkan untuk mencari dan JSON untuk orang lain, bukan?
ShuklaSannidhya
4
Iya. dengan cara itu, Anda mendapatkan kinerja yang diperlukan dari pencarian bidang data-per-kolom, dan ambil gumpalan JSON untuk digunakan dalam kode bila diperlukan.
Nick Andriopoulos
9

Pada dasarnya, model pertama yang Anda gunakan disebut sebagai penyimpanan berbasis dokumen. Anda harus melihat pada basis data berbasis dokumen NoSQL yang populer seperti MongoDB dan CouchDB . Pada dasarnya, dalam db berbasis dokumen, Anda menyimpan data dalam file json dan kemudian Anda dapat meminta file json ini.

Model kedua adalah struktur basis data relasional yang populer.

Jika Anda ingin menggunakan database relasional seperti MySql maka saya akan menyarankan Anda untuk hanya menggunakan model kedua. Tidak ada gunanya menggunakan MySql dan menyimpan data seperti pada model pertama .

Untuk menjawab pertanyaan kedua Anda, tidak ada cara untuk menanyakan nama seperti 'foo' jika Anda menggunakan model pertama .

Girish
sumber
Apakah bijaksana menggunakan kedua model? Kunci-per-kolom untuk data yang saya butuhkan untuk mencari dan JSON untuk orang lain (dalam database yang sama)?
ShuklaSannidhya
@Sann - haha. Itu duplikasi data. Anda harus memastikan bahwa kedua keping data selalu sama. Bahkan jika salah satu datanya berbeda di setiap titik waktu, maka data Anda tidak bersih dan dapat menyebabkan masalah serius. Jadi, jawaban saya adalah TIDAK
Girish
Tapi redundansi tidak mahal ketika data redundan kecil, katakanlah, hanya ada dua bidang yang harus saya lakukan pencarian, jadi saya membuat dua kolom baru untuk mereka, [mungkin] menghapusnya dari data JSON saya [/ mungkin] . Itu bukan duplikasi yang mahal kan?
ShuklaSannidhya
Jika Anda melihat kinerja, maka MongoDB dan CouchDB menyediakan operasi baca dan tulis yang lebih cepat daripada MySql karena mereka tidak menawarkan banyak fitur dalam basis data relasional yang tidak diperlukan dalam sebagian besar kasus penggunaan.
Girish
Tidak bisakah manfaatnya menyimpan objek / panggilan balik JSON dari API? Misalnya, alih-alih memanggil API YouTube untuk URL, ibu jari, dll, Anda bisa meminta DB lokal Anda (mysql, lite, dll) untuk objek JSON? Saya tidak tahu, masuk akal bagi saya, terutama jika Anda mencoba untuk melakukan cache atau membuat aplikasi berjalan lebih cepat. Tapi aku bukan profesional: /
markbratanov
4

Tampaknya Anda terutama ragu apakah akan menggunakan model relasional atau tidak.

Seperti contohnya, contoh Anda akan cocok dengan model relasional dengan cukup baik, tetapi masalahnya mungkin muncul ketika Anda perlu membuat model ini berkembang.

Jika Anda hanya memiliki satu (atau beberapa tingkat yang ditentukan sebelumnya) atribut untuk entitas utama Anda (pengguna), Anda masih bisa menggunakan model Nilai Atribut Nilai Entitas (EAV) dalam database relasional. (Ini juga memiliki pro dan kontra.)

Jika Anda mengantisipasi bahwa Anda akan mendapatkan nilai yang kurang terstruktur yang ingin Anda cari menggunakan aplikasi Anda, MySQL mungkin bukan pilihan terbaik di sini.

Jika Anda menggunakan PostgreSQL, Anda berpotensi mendapatkan yang terbaik dari kedua dunia. (Ini benar-benar tergantung pada struktur data yang sebenarnya di sini ... MySQL juga bukan pilihan yang salah, dan opsi NoSQL bisa menarik, saya hanya menyarankan alternatif.)

Memang, PostgreSQL dapat membangun indeks pada fungsi-fungsi (yang tidak dapat diubah) (yang tidak dapat saya ketahui sejauh MySQL) dan dalam versi terbaru, Anda dapat menggunakan PLV8 pada data JSON secara langsung untuk membangun indeks pada elemen-elemen minat JSON tertentu, yang akan meningkatkan kecepatan pertanyaan Anda saat mencari data itu.

EDIT:

Karena tidak akan ada terlalu banyak kolom di mana saya perlu melakukan pencarian, apakah sebaiknya menggunakan kedua model? Kunci-per-kolom untuk data yang saya butuhkan untuk mencari dan JSON untuk orang lain (dalam database MySQL yang sama)?

Menggabungkan kedua model tidak selalu salah (dengan asumsi ruang tambahan dapat diabaikan), tetapi dapat menyebabkan masalah jika Anda tidak memastikan dua set data tetap sinkron: aplikasi Anda tidak boleh mengubah satu tanpa harus memperbarui yang lain .

Cara yang baik untuk mencapai ini adalah memiliki pemicu melakukan pembaruan otomatis, dengan menjalankan prosedur yang tersimpan dalam server database setiap kali pembaruan atau penyisipan dilakukan. Sejauh yang saya ketahui, bahasa prosedur tersimpan MySQL mungkin kurang mendukung untuk segala jenis pemrosesan JSON. Lagi PostgreSQL dengan dukungan PLV8 (dan mungkin RDBMS lainnya dengan bahasa prosedur tersimpan yang lebih fleksibel) harus lebih bermanfaat (memperbarui kolom relasional Anda secara otomatis menggunakan pemicu sangat mirip dengan memperbarui indeks dengan cara yang sama).

Bruno
sumber
Selain apa yang saya katakan di atas, bisa bernilai melihat operator untuk tipe data JSONB di PostgreSQL 9.4 dan di atas.
Bruno
1

beberapa waktu bergabung di atas meja akan menjadi overhead. katakanlah untuk OLAP. jika saya memiliki dua tabel, satu adalah tabel PESANAN dan yang lainnya adalah ORDER_DETAILS. Untuk mendapatkan semua detail pesanan, kita harus menggabungkan dua tabel, ini akan membuat kueri lebih lambat ketika tidak ada baris dalam tabel yang bertambah, katakanlah dalam jutaan atau lebih .. gabung kiri / kanan terlalu lambat daripada gabung dalam. Saya pikir jika kita menambahkan string JSON / Objek dalam entri PESANAN masing-masing BERGABUNG akan dihindari. tambah pembuatan laporan akan lebih cepat ...

Ravindra
sumber
1

jawaban singkat Anda harus mencampur di antara mereka, gunakan json untuk data yang Anda tidak akan membuat hubungan dengan mereka seperti data kontak, alamat, berbagai produk

Ahmedfraije Aa
sumber
0

Anda mencoba memasukkan model non-relasional ke dalam basis data relasional, saya pikir Anda akan lebih baik dilayani menggunakan database NoSQL seperti MongoDB . Tidak ada skema standar yang sesuai dengan kebutuhan Anda untuk tidak membatasi jumlah bidang (lihat contoh koleksi MongoDB khas). Periksa dokumentasi MongoDB untuk mendapatkan gambaran tentang bagaimana Anda akan menanyakan dokumen Anda, misalnya

db.mycollection.find(
    {
      name: 'sann'
    }
)
Chris L.
sumber
2
Karena penasaran, apa yang membuat Anda berasumsi bahwa modelnya adalah non-relasional. Informasi yang dia berikan di atas nampaknya sangat berhubungan dengan saya.
Colin M
0

Seperti orang lain telah menunjukkan pertanyaan akan lebih lambat. Saya sarankan untuk menambahkan setidaknya kolom '_ID' ke permintaan dengan itu.

Celana
sumber